diff --git a/.betterer.results b/.betterer.results index 5532fe46780..fa273770d62 100644 --- a/.betterer.results +++ b/.betterer.results @@ -5,33 +5,13 @@ // exports[`too-much-lint`] = { value: `{ - "types/foundry/client/application/form-application/document-sheet/actor-sheet.d.ts:4046500136": [ - [8, 15, 3, "Unexpected any. Specify a different type.", "193409811"], - [9, 14, 3, "Unexpected any. Specify a different type.", "193409811"], - [10, 15, 3, "Unexpected any. Specify a different type.", "193409811"] + "types/foundry/client/application/form-application/document-sheet/actor-sheet.d.ts:2380220550": [ + [9, 15, 3, "Unexpected any. Specify a different type.", "193409811"], + [10, 14, 3, "Unexpected any. Specify a different type.", "193409811"], + [11, 15, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "types/foundry/client/collections/compendium-collection.d.ts:775132723": [ - [246, 23, 3, "Unexpected any. Specify a different type.", "193409811"] - ], - "types/foundry/client/documents/mixins/canvas-document-mixin.d.ts:3303075782": [ - [16, 22, 3, "Unexpected any. Specify a different type.", "193409811"], - [21, 57, 3, "Unexpected any. Specify a different type.", "193409811"], - [54, 57, 3, "Unexpected any. Specify a different type.", "193409811"] - ], - "types/foundry/client/documents/mixins/client-document-mixin.d.ts:1499800974": [ - [8, 18, 3, "Unexpected any. Specify a different type.", "193409811"], - [65, 43, 3, "Unexpected any. Specify a different type.", "193409811"], - [309, 44, 3, "Unexpected any. Specify a different type.", "193409811"] - ], - "types/foundry/client/pixi/placeables-layer/base.d.ts:7710705": [ - [134, 20, 3, "Unexpected any. Specify a different type.", "193409811"], - [158, 20, 3, "Unexpected any. Specify a different type.", "193409811"], - [164, 31, 3, "Unexpected any. Specify a different type.", "193409811"], - [174, 25, 3, "Unexpected any. Specify a different type.", "193409811"], - [174, 42, 3, "Unexpected any. Specify a different type.", "193409811"], - [174, 56, 3, "Unexpected any. Specify a different type.", "193409811"], - [186, 44, 3, "Unexpected any. Specify a different type.", "193409811"], - [186, 58, 3, "Unexpected any. Specify a different type.", "193409811"] + "types/foundry/client/collections/compendium-collection.d.ts:447575351": [ + [251, 23, 3, "Unexpected any. Specify a different type.", "193409811"] ], "types/foundry/client/ui/filepicker.d.ts:274431795": [ [9, 13, 3, "Unexpected any. Specify a different type.", "193409811"], @@ -44,9 +24,6 @@ exports[`too-much-lint`] = { [128, 45, 3, "Unexpected any. Specify a different type.", "193409811"], [138, 36, 3, "Unexpected any. Specify a different type.", "193409811"], [143, 44, 3, "Unexpected any. Specify a different type.", "193409811"] - ], - "types/foundry/common/abstract/data.d.ts:2798586197": [ - [25, 34, 3, "Unexpected any. Specify a different type.", "193409811"] ] }` }; diff --git a/package-lock.json b/package-lock.json index 60463e390a2..7000a38a6d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,26 +36,26 @@ "@types/jquery": "^3.5.16", "@types/jsdom": "^21.1.0", "@types/luxon": "^3.2.0", - "@types/node": "^18.15.3", + "@types/node": "^18.15.5", "@types/sortablejs": "^1.15.1", "@types/tooltipster": "^0.0.31", "@types/webpack-env": "^1.18.0", "@types/yaireo__tagify": "^4.16.1", - "@typescript-eslint/eslint-plugin": "^5.55.0", - "@typescript-eslint/parser": "^5.55.0", + "@typescript-eslint/eslint-plugin": "^5.56.0", + "@typescript-eslint/parser": "^5.56.0", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.7.3", "css-minimizer-webpack-plugin": "^4.2.2", "eslint": "^8.36.0", - "eslint-config-prettier": "^8.7.0", + "eslint-config-prettier": "^8.8.0", "eslint-import-resolver-typescript": "^3.5.3", "eslint-plugin-import": "^2.27.5", "eslint-plugin-jest": "^27.2.1", "eslint-plugin-json": "^3.1.0", "eslint-plugin-prettier": "^4.2.1", "fork-ts-checker-webpack-plugin": "^8.0.0", - "fs-extra": "^11.1.0", - "glob": "^9.3.0", + "fs-extra": "^11.1.1", + "glob": "^9.3.1", "gsap": "^3.11.0", "handlebars": "4.7.7", "jest": "^29.5.0", @@ -63,10 +63,10 @@ "mini-css-extract-plugin": "^2.7.5", "null-loader": "^4.0.1", "pixi.js": "6.5.2", - "prettier": "^2.8.4", + "prettier": "^2.8.5", "raw-loader": "^4.0.2", "sass": "^1.59.3", - "sass-loader": "^13.2.0", + "sass-loader": "^13.2.1", "simple-progress-webpack-plugin": "^2.0.0", "socket.io": "4.5.1", "socket.io-client": "4.5.1", @@ -77,10 +77,10 @@ "ts-loader": "^9.4.2", "ts-node": "^10.9.1", "tsconfig-paths": "^4.1.2", - "typescript": "^4.9.5", + "typescript": "^5.0.2", "webpack": "^5.76.2", "webpack-cli": "^5.0.1", - "webpack-dev-server": "^4.12.0", + "webpack-dev-server": "^4.13.1", "webpack-import-glob-loader": "^1.6.3", "write-file-webpack-plugin": "^4.5.1" } @@ -764,6 +764,20 @@ "typescript": "^3 || ^4" } }, + "node_modules/@betterer/cli/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/@betterer/constraints": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@betterer/constraints/-/constraints-5.3.0.tgz", @@ -2312,9 +2326,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.15.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz", - "integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==", + "version": "18.15.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz", + "integrity": "sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==", "dev": true }, "node_modules/@types/offscreencanvas": { @@ -2484,15 +2498,15 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz", - "integrity": "sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.56.0.tgz", + "integrity": "sha512-ZNW37Ccl3oMZkzxrYDUX4o7cnuPgU+YrcaYXzsRtLB16I1FR5SHMqga3zGsaSliZADCWo2v8qHWqAYIj8nWCCg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/type-utils": "5.55.0", - "@typescript-eslint/utils": "5.55.0", + "@typescript-eslint/scope-manager": "5.56.0", + "@typescript-eslint/type-utils": "5.56.0", + "@typescript-eslint/utils": "5.56.0", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -2518,14 +2532,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz", - "integrity": "sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.56.0.tgz", + "integrity": "sha512-sn1OZmBxUsgxMmR8a8U5QM/Wl+tyqlH//jTqCg8daTAmhAk26L2PFhcqPLlYBhYUJMZJK276qLXlHN3a83o2cg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/typescript-estree": "5.55.0", + "@typescript-eslint/scope-manager": "5.56.0", + "@typescript-eslint/types": "5.56.0", + "@typescript-eslint/typescript-estree": "5.56.0", "debug": "^4.3.4" }, "engines": { @@ -2545,13 +2559,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz", - "integrity": "sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.56.0.tgz", + "integrity": "sha512-jGYKyt+iBakD0SA5Ww8vFqGpoV2asSjwt60Gl6YcO8ksQ8s2HlUEyHBMSa38bdLopYqGf7EYQMUIGdT/Luw+sw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/visitor-keys": "5.55.0" + "@typescript-eslint/types": "5.56.0", + "@typescript-eslint/visitor-keys": "5.56.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2562,13 +2576,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz", - "integrity": "sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.56.0.tgz", + "integrity": "sha512-8WxgOgJjWRy6m4xg9KoSHPzBNZeQbGlQOH7l2QEhQID/+YseaFxg5J/DLwWSsi9Axj4e/cCiKx7PVzOq38tY4A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.55.0", - "@typescript-eslint/utils": "5.55.0", + "@typescript-eslint/typescript-estree": "5.56.0", + "@typescript-eslint/utils": "5.56.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -2589,9 +2603,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", - "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.56.0.tgz", + "integrity": "sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2602,13 +2616,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", - "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.56.0.tgz", + "integrity": "sha512-41CH/GncsLXOJi0jb74SnC7jVPWeVJ0pxQj8bOjH1h2O26jXN3YHKDT1ejkVz5YeTEQPeLCCRY0U2r68tfNOcg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/visitor-keys": "5.55.0", + "@typescript-eslint/types": "5.56.0", + "@typescript-eslint/visitor-keys": "5.56.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2629,17 +2643,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz", - "integrity": "sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.56.0.tgz", + "integrity": "sha512-XhZDVdLnUJNtbzaJeDSCIYaM+Tgr59gZGbFuELgF7m0IY03PlciidS7UQNKLE0+WpUTn1GlycEr6Ivb/afjbhA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.55.0", - "@typescript-eslint/types": "5.55.0", - "@typescript-eslint/typescript-estree": "5.55.0", + "@typescript-eslint/scope-manager": "5.56.0", + "@typescript-eslint/types": "5.56.0", + "@typescript-eslint/typescript-estree": "5.56.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, @@ -2655,12 +2669,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", - "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.56.0.tgz", + "integrity": "sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/types": "5.56.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -4955,9 +4969,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz", - "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -5942,9 +5956,9 @@ } }, "node_modules/fs-extra": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", - "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -6090,9 +6104,9 @@ } }, "node_modules/glob": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.0.tgz", - "integrity": "sha512-EAZejC7JvnQINayvB/7BJbpZpNOJ8Lrw2OZNEvQxe0vaLn1SuwMcfV7/MNaX8L/T0wmptBFI4YMtDvSBxYDc7w==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.1.tgz", + "integrity": "sha512-qERvJb7IGsnkx6YYmaaGvDpf77c951hICMdWaFXyH3PlVob8sbPJJyJX0kWkiCWyXUzoy9UOTNjGg0RbD8bYIw==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -7955,9 +7969,9 @@ } }, "node_modules/klona": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", "dev": true, "engines": { "node": ">= 8" @@ -10030,9 +10044,9 @@ } }, "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.5.tgz", + "integrity": "sha512-3gzuxrHbKUePRBB4ZeU08VNkUcqEHaUaouNt0m7LGP4Hti/NuB07C7PPTM/LkWqXoJYJn2McEo5+kxPNrtQkLQ==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -10618,12 +10632,12 @@ } }, "node_modules/sass-loader": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", - "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.1.tgz", + "integrity": "sha512-VQUrgUa5/waIzMrzyuko3sj5WD9NMsYph91cNICx+OaODbRtLl6To2fswLx8MH2qNxXFqRtpvdPQIa7mE93YOA==", "dev": true, "dependencies": { - "klona": "^2.0.4", + "klona": "^2.0.6", "neo-async": "^2.6.2" }, "engines": { @@ -11969,16 +11983,16 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.20" } }, "node_modules/uglify-js": { @@ -12383,9 +12397,9 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.12.0.tgz", - "integrity": "sha512-XRN9YRnvOj3TQQ5w/0pR1y1xDcVnbWtNkTri46kuEbaWUPTHsWUvOyAAI7PZHLY+hsFki2kRltJjKMw7e+IiqA==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.1.tgz", + "integrity": "sha512-5tWg00bnWbYgkN+pd5yISQKDejRBYGEw15RaEEslH+zdbNDxxaZvEAO2WulaSaFKb5n3YG8JXsGaDsut1D0xdA==", "dev": true, "dependencies": { "@types/bonjour": "^3.5.9", @@ -12433,6 +12447,9 @@ "webpack": "^4.37.0 || ^5.0.0" }, "peerDependenciesMeta": { + "webpack": { + "optional": true + }, "webpack-cli": { "optional": true } diff --git a/package.json b/package.json index 77a956a3f59..26ee4c4ee8f 100644 --- a/package.json +++ b/package.json @@ -32,26 +32,26 @@ "@types/jquery": "^3.5.16", "@types/jsdom": "^21.1.0", "@types/luxon": "^3.2.0", - "@types/node": "^18.15.3", + "@types/node": "^18.15.5", "@types/sortablejs": "^1.15.1", "@types/tooltipster": "^0.0.31", "@types/webpack-env": "^1.18.0", "@types/yaireo__tagify": "^4.16.1", - "@typescript-eslint/eslint-plugin": "^5.55.0", - "@typescript-eslint/parser": "^5.55.0", + "@typescript-eslint/eslint-plugin": "^5.56.0", + "@typescript-eslint/parser": "^5.56.0", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.7.3", "css-minimizer-webpack-plugin": "^4.2.2", "eslint": "^8.36.0", - "eslint-config-prettier": "^8.7.0", + "eslint-config-prettier": "^8.8.0", "eslint-import-resolver-typescript": "^3.5.3", "eslint-plugin-import": "^2.27.5", "eslint-plugin-jest": "^27.2.1", "eslint-plugin-json": "^3.1.0", "eslint-plugin-prettier": "^4.2.1", "fork-ts-checker-webpack-plugin": "^8.0.0", - "fs-extra": "^11.1.0", - "glob": "^9.3.0", + "fs-extra": "^11.1.1", + "glob": "^9.3.1", "gsap": "^3.11.0", "handlebars": "4.7.7", "jest": "^29.5.0", @@ -59,10 +59,10 @@ "mini-css-extract-plugin": "^2.7.5", "null-loader": "^4.0.1", "pixi.js": "6.5.2", - "prettier": "^2.8.4", + "prettier": "^2.8.5", "raw-loader": "^4.0.2", "sass": "^1.59.3", - "sass-loader": "^13.2.0", + "sass-loader": "^13.2.1", "simple-progress-webpack-plugin": "^2.0.0", "socket.io": "4.5.1", "socket.io-client": "4.5.1", @@ -73,10 +73,10 @@ "ts-loader": "^9.4.2", "ts-node": "^10.9.1", "tsconfig-paths": "^4.1.2", - "typescript": "^4.9.5", + "typescript": "^5.0.2", "webpack": "^5.76.2", "webpack-cli": "^5.0.1", - "webpack-dev-server": "^4.12.0", + "webpack-dev-server": "^4.13.1", "webpack-import-glob-loader": "^1.6.3", "write-file-webpack-plugin": "^4.5.1" }, diff --git a/packs/scripts/extract.ts b/packs/scripts/extract.ts index ae1cc9bd288..79900bdc0d0 100644 --- a/packs/scripts/extract.ts +++ b/packs/scripts/extract.ts @@ -114,7 +114,7 @@ const npcSystemKeys = new Set([ const idsToNames: Map> = new Map(); -type CompendiumDocumentPF2e = ActorPF2e | ItemPF2e | JournalEntry | MacroPF2e | RollTable; +type CompendiumDocumentPF2e = ActorPF2e | ItemPF2e | JournalEntry | MacroPF2e | RollTable; type PackEntry = CompendiumDocumentPF2e["_source"]; function assertDocIdSame(newSource: PackEntry, jsonPath: string): void { diff --git a/packs/scripts/run-migration.ts b/packs/scripts/run-migration.ts index 0ec377c3f2b..72adc092327 100644 --- a/packs/scripts/run-migration.ts +++ b/packs/scripts/run-migration.ts @@ -138,11 +138,11 @@ const isJournalEntryData = (docSource: CompendiumSource): docSource is foundry.d return "pages" in docSource && Array.isArray(docSource.pages); }; -const isMacroData = (docSource: CompendiumSource): docSource is foundry.data.MacroSource => { +const isMacroData = (docSource: CompendiumSource): docSource is foundry.documents.MacroSource => { return "type" in docSource && ["chat", "script"].includes(docSource.type); }; -const isTableData = (docSource: CompendiumSource): docSource is foundry.data.RollTableSource => { +const isTableData = (docSource: CompendiumSource): docSource is foundry.documents.RollTableSource => { return "results" in docSource && Array.isArray(docSource.results); }; @@ -201,8 +201,8 @@ async function migrate() { | ActorSourcePF2e | ItemSourcePF2e | foundry.documents.JournalEntrySource - | foundry.data.MacroSource - | foundry.data.RollTableSource; + | foundry.documents.MacroSource + | foundry.documents.RollTableSource; try { // Parse file content source = JSON.parse(content); @@ -217,8 +217,8 @@ async function migrate() { | ActorSourcePF2e | ItemSourcePF2e | foundry.documents.JournalEntrySource - | foundry.data.MacroSource - | foundry.data.RollTableSource + | foundry.documents.MacroSource + | foundry.documents.RollTableSource > => { source.flags ??= {}; try { diff --git a/src/global.d.ts b/src/global.d.ts index 0d5b9a24454..0773c0556b3 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1,7 +1,7 @@ import { ActorPF2e } from "@actor/base"; import { AutomaticBonusProgression } from "@actor/character/automatic-bonus-progression"; import { FeatCategoryOptions } from "@actor/character/feats"; -import { CheckModifier, ModifierPF2e, MODIFIER_TYPE, StatisticModifier } from "@actor/modifiers"; +import { CheckModifier, MODIFIER_TYPE, ModifierPF2e, StatisticModifier } from "@actor/modifiers"; import { ItemPF2e } from "@item/base"; import { CoinsPF2e } from "@item/physical/helpers"; import { ActiveEffectPF2e } from "@module/active-effect"; @@ -48,14 +48,14 @@ import { ConditionManager } from "./module/system/conditions"; declare global { interface Game< - TActor extends Actor, + TActor extends Actor, TActors extends Actors, - TChatMessage extends ChatMessage, + TChatMessage extends ChatMessage, TCombat extends Combat, - TItem extends Item, + TItem extends Item, TMacro extends Macro, TScene extends Scene, - TUser extends User + TUser extends User > { pf2e: { actions: Record; @@ -111,10 +111,25 @@ declare global { namespace globalThis { // eslint-disable-next-line no-var - var game: Game; + var game: Game< + ActorPF2e, + ActorsPF2e>, + ChatMessagePF2e, + EncounterPF2e, + ItemPF2e, + MacroPF2e, + ScenePF2e, + UserPF2e + >; // eslint-disable-next-line no-var - var ui: FoundryUI, ItemPF2e, ChatLogPF2e, CompendiumDirectoryPF2e>; + var ui: FoundryUI< + ActorPF2e, + ActorDirectoryPF2e>, + ItemPF2e, + ChatLogPF2e, + CompendiumDirectoryPF2e + >; } interface Window { @@ -201,14 +216,13 @@ declare global { } type ConfiguredConfig = Config< - AmbientLightDocumentPF2e, - ActiveEffectPF2e, + AmbientLightDocumentPF2e, + ActiveEffectPF2e, ActorPF2e, - ActorDirectoryPF2e, ChatLogPF2e, ChatMessagePF2e, EncounterPF2e, - CombatantPF2e, + CombatantPF2e, EncounterTrackerPF2e, CompendiumDirectoryPF2e, HotbarPF2e, @@ -219,6 +233,6 @@ type ConfiguredConfig = Config< TokenDocumentPF2e, WallDocument, ScenePF2e, - UserPF2e, + UserPF2e, EffectsCanvasGroupPF2e >; diff --git a/src/module/active-effect.ts b/src/module/active-effect.ts index fd07b71ec01..a164c6bc8b0 100644 --- a/src/module/active-effect.ts +++ b/src/module/active-effect.ts @@ -1,8 +1,10 @@ +import { ActorPF2e, ItemPF2e } from "./documents"; + /** Disable Active Effects */ -export class ActiveEffectPF2e extends ActiveEffect { +export class ActiveEffectPF2e extends ActiveEffect { constructor( - data: DeepPartial, - context?: DocumentConstructionContext + data: DeepPartial, + context?: DocumentConstructionContext ) { data.disabled = true; data.transfer = false; diff --git a/src/module/actor/base.ts b/src/module/actor/base.ts index 1d34d3f3471..ef2fc84a855 100644 --- a/src/module/actor/base.ts +++ b/src/module/actor/base.ts @@ -1,11 +1,13 @@ import { ActorAlliance, ActorDimensions, + ActorInstances, ApplyDamageParams, AttackItem, AttackRollContext, AttackRollContextParams, AuraData, + EmbeddedItemInstances, SaveType, StrikeRollContext, StrikeRollContextParams, @@ -23,10 +25,11 @@ import { hasInvestedProperty } from "@item/data/helpers"; import { EffectFlags, EffectSource } from "@item/effect/data"; import { RitualSpellcasting } from "@item/spellcasting-entry/rituals"; import type { ActiveEffectPF2e } from "@module/active-effect"; +import { TokenPF2e } from "@module/canvas"; import { ChatMessagePF2e } from "@module/chat-message"; import { OneToThree, Size } from "@module/data"; import { preImportJSON } from "@module/doc-helpers"; -import { CombatantPF2e, EncounterPF2e } from "@module/encounter"; +import { EncounterPF2e, RolledCombatant } from "@module/encounter"; import { RuleElementSynthetics } from "@module/rules"; import { extractEphemeralEffects, processPreUpdateActorHooks } from "@module/rules/helpers"; import { RuleElementPF2e } from "@module/rules/rule-element/base"; @@ -34,10 +37,10 @@ import { RollOptionRuleElement } from "@module/rules/rule-element/roll-option"; import { RollOptionToggle } from "@module/rules/synthetics"; import { LocalizePF2e } from "@module/system/localize"; import { UserPF2e } from "@module/user"; -import { TokenDocumentPF2e } from "@scene"; +import { ScenePF2e, TokenDocumentPF2e } from "@scene"; import { DicePF2e } from "@scripts/dice"; import { DamageType } from "@system/damage"; -import { applyIWR, IWRApplicationData, maxPersistentAfterIWR } from "@system/damage/iwr"; +import { IWRApplicationData, applyIWR, maxPersistentAfterIWR } from "@system/damage/iwr"; import { Statistic, StatisticCheck } from "@system/statistic"; import { TextEditorPF2e } from "@system/text-editor"; import { @@ -50,7 +53,6 @@ import { traitSlugToObject, tupleHasValue, } from "@util"; -import type { CreaturePF2e } from "./creature"; import { VisionLevel, VisionLevels } from "./creature/data"; import { GetReachParameters, ModeOfBeing } from "./creature/types"; import { ActorSourcePF2e, ActorType } from "./data"; @@ -77,7 +79,7 @@ import { CREATURE_ACTOR_TYPES, UNAFFECTED_TYPES } from "./values"; * Extend the base Actor class to implement additional logic specialized for PF2e. * @category Actor */ -class ActorPF2e extends Actor { +class ActorPF2e extends Actor { /** Has this actor completed construction? */ private constructed = true; @@ -85,10 +87,10 @@ class ActorPF2e extends Actor { preparingEmbeds?: boolean; /** A separate collection of owned physical items for convenient access */ - inventory!: ActorInventory; + inventory!: ActorInventory; /** A separate collection of owned spellcasting entries for convenience */ - spellcasting!: ActorSpellcasting; + spellcasting!: ActorSpellcasting; /** Rule elements drawn from owned items */ rules!: RuleElementPF2e[]; @@ -102,12 +104,12 @@ class ActorPF2e extends Actor { auras!: Map; /** Conditions this actor has */ - conditions!: Map; + conditions!: Map>; /** A cached copy of `Actor#itemTypes`, lazily regenerated every data preparation cycle */ - private _itemTypes?: { [K in keyof ItemTypeMap]: Embedded[] } | null; + private _itemTypes?: EmbeddedItemInstances | null; - constructor(data: PreCreate, context: DocumentConstructionContext = {}) { + constructor(data: PreCreate, context: DocumentConstructionContext = {}) { super(data, context); // Add debounced checkAreaEffects method @@ -120,8 +122,8 @@ class ActorPF2e extends Actor { } /** Cache the return data before passing it to the caller */ - override get itemTypes(): { [K in keyof ItemTypeMap]: Embedded[] } { - return (this._itemTypes ??= super.itemTypes); + override get itemTypes(): EmbeddedItemInstances { + return (this._itemTypes ??= super.itemTypes as EmbeddedItemInstances); } get allowedItemTypes(): (ItemType | "physical")[] { @@ -254,7 +256,7 @@ class ActorPF2e extends Actor { } /** Get the actor's held shield. Meaningful implementation in `CreaturePF2e`'s override. */ - get heldShield(): Embedded | null { + get heldShield(): ArmorPF2e | null { return null; } @@ -284,13 +286,7 @@ class ActorPF2e extends Actor { } /** A means of checking this actor's type without risk of circular import references */ - isOfType(type: "creature"): this is CreaturePF2e; - isOfType( - ...types: T[] - ): this is InstanceType; - isOfType( - ...types: T[] - ): this is CreaturePF2e | InstanceType]>; + isOfType(...types: T[]): this is ActorInstances[T]; isOfType(...types: string[]): boolean { return types.some((t) => (t === "creature" ? tupleHasValue(CREATURE_ACTOR_TYPES, this.type) : this.type === t)); } @@ -434,15 +430,27 @@ class ActorPF2e extends Actor { } /** Don't allow the user to create in development actor types. */ + static override createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; static override async createDialog( data: { folder?: string | undefined } = {}, - options: Partial = {} - ): Promise | undefined> { + options: { + parent?: TokenDocumentPF2e | null; + pack?: Collection> | null; + [key: string]: unknown; + } = {} + ): Promise | null> | null> { const original = game.system.documentTypes.Actor; game.system.documentTypes.Actor = original.filter( (actorType: string) => actorType !== "party" || BUILD_MODE !== "production" ); - const newActor = super.createDialog(data, options) as Promise; + const newActor = super.createDialog(data, options); game.system.documentTypes.Actor = original; return newActor; } @@ -451,15 +459,15 @@ class ActorPF2e extends Actor { * As of Foundry 0.8: All subclasses of ActorPF2e need to use this factory method rather than having their own * overrides, since Foundry itself will call `ActorPF2e.create` when a new actor is created from the sidebar. */ - static override async createDocuments( - this: ConstructorOf, - data?: (T | PreCreate)[], - context?: DocumentModificationContext - ): Promise; + static override async createDocuments( + this: ConstructorOf, + data?: (TDocument | PreCreate)[], + context?: DocumentModificationContext + ): Promise; static override async createDocuments( data: (ActorPF2e | PreCreate)[] = [], - context: DocumentModificationContext = {} - ): Promise { + context: DocumentModificationContext = {} + ): Promise | null>[]> { // Convert all `ActorPF2e`s to source objects const sources = data.map((d) => (d instanceof ActorPF2e ? d.toObject() : d)); @@ -509,15 +517,15 @@ class ActorPF2e extends Actor { return super.createDocuments(sources, context); } - static override updateDocuments( - this: ConstructorOf, - updates?: DocumentUpdateData[], - context?: DocumentModificationContext - ): Promise; + static override updateDocuments( + this: ConstructorOf, + updates?: DocumentUpdateData[], + context?: DocumentUpdateContext + ): Promise; static override async updateDocuments( updates: DocumentUpdateData[] = [], - context: DocumentModificationContext = {} - ): Promise { + context: DocumentModificationContext = {} + ): Promise | null>[]> { // Process rule element hooks for each actor update for (const changed of updates) { await processPreUpdateActorHooks(changed, { pack: context.pack ?? null }); @@ -575,7 +583,7 @@ class ActorPF2e extends Actor { /** Set module art if available */ protected override _initializeSource( source: Record, - options?: DocumentConstructionContext + options?: DocumentConstructionContext ): this["_source"] { const initialized = super._initializeSource(source, options); @@ -650,12 +658,10 @@ class ActorPF2e extends Actor { super.prepareEmbeddedDocuments(); this.preparingEmbeds = false; - const physicalItems: Embedded[] = this.items.filter( - (item) => item instanceof PhysicalItemPF2e - ); + const physicalItems = this.items.filter((i): i is PhysicalItemPF2e => i.isOfType("physical")); this.inventory = new ActorInventory(this, physicalItems); - this.spellcasting = ((): ActorSpellcasting => { + this.spellcasting = ((): ActorSpellcasting => { const rituals = this.itemTypes.spell.filter((s) => s.isRitual).sort((a, b) => a.sort - b.sort); const spellcastingEntries = [ this.itemTypes.spellcastingEntry, @@ -726,7 +732,9 @@ class ActorPF2e extends Actor { if (!encounter?.started) return; const participants = encounter.combatants.contents - .filter((c): c is CombatantPF2e & { initiative: number } => typeof c.initiative === "number") + .filter( + (c): c is RolledCombatant & { initiative: number } => typeof c.initiative === "number" + ) .sort((a, b) => b.initiative - a.initiative); // Sort descending by initiative roll result const participant = participants.find((c) => c.actor === this); if (typeof participant?.initiative !== "number") return; @@ -1197,7 +1205,7 @@ class ActorPF2e extends Actor { const persistentCreated = ( persistentDamage.length > 0 ? await this.createEmbeddedDocuments("Item", persistentDamage) : [] - ) as ConditionPF2e[]; + ) as ConditionPF2e[]; const content = await renderTemplate("systems/pf2e/templates/chat/damage/damage-taken.hbs", { statements, @@ -1235,11 +1243,11 @@ class ActorPF2e extends Actor { */ async transferItemToActor( targetActor: ActorPF2e, - item: Embedded, + item: ItemPF2e, quantity: number, containerId?: string, newStack = false - ): Promise | null> { + ): Promise | null> { if (!(item instanceof PhysicalItemPF2e)) { throw ErrorPF2e("Only physical items (with quantities) can be transfered between actors"); } @@ -1296,9 +1304,9 @@ class ActorPF2e extends Actor { async addToInventory( itemSource: PhysicalItemSource, - container?: Embedded, + container?: ContainerPF2e, newStack?: boolean - ): Promise | null> { + ): Promise | null> { // Stack with an existing item if possible const stackItem = this.findStackableItem(this, itemSource); if (!newStack && stackItem && stackItem.type !== "backpack") { @@ -1320,7 +1328,7 @@ class ActorPF2e extends Actor { } /** Find an item already owned by the actor that can stack with the to-be-transferred item */ - findStackableItem(actor: ActorPF2e, itemSource: ItemSourcePF2e): Embedded | null { + findStackableItem(actor: TActor, itemSource: ItemSourcePF2e): PhysicalItemPF2e | null { // Prevent upstream from mutating property descriptors const testItem = new ItemProxyPF2e(deepClone(itemSource)); const stackCandidates = actor.inventory.filter( @@ -1342,7 +1350,7 @@ class ActorPF2e extends Actor { } /** Move an item into the inventory into or out of a container */ - async stowOrUnstow(item: Embedded, container?: Embedded): Promise { + async stowOrUnstow(item: PhysicalItemPF2e, container?: ContainerPF2e): Promise { if (!container) { await item.update({ "system.containerId": null, @@ -1446,7 +1454,7 @@ class ActorPF2e extends Actor { getCondition( slug: ConditionKey, { all }: { all: boolean } = { all: false } - ): Embedded[] | Embedded | null { + ): ConditionPF2e[] | ConditionPF2e | null { const conditions = this.itemTypes.condition.filter( (condition) => condition.key === slug || condition.slug === slug ); @@ -1471,7 +1479,7 @@ class ActorPF2e extends Actor { /** Decrease the value of condition or remove it entirely */ async decreaseCondition( - conditionSlug: ConditionKey | Embedded, + conditionSlug: ConditionKey | ConditionPF2e, { forceRemove }: { forceRemove: boolean } = { forceRemove: false } ): Promise { // Find a valid matching condition if a slug was passed @@ -1495,13 +1503,13 @@ class ActorPF2e extends Actor { /** Increase a valued condition, or create a new one if not present */ async increaseCondition( - conditionSlug: ConditionSlug | Embedded, + conditionSlug: ConditionSlug | ConditionPF2e, { min, max = Number.MAX_SAFE_INTEGER, value, }: { min?: number | null; max?: number | null; value?: number | null } = {} - ): Promise { + ): Promise | null> { if (value) min = max = value; // Persistent damage goes through a dialog instead @@ -1539,7 +1547,7 @@ class ActorPF2e extends Actor { ? Math.clamped(conditionSource.system.value.value, min, max) : null; conditionSource.system.value.value = conditionValue; - const items = (await this.createEmbeddedDocuments("Item", [conditionSource])) as ConditionPF2e[]; + const items = (await this.createEmbeddedDocuments("Item", [conditionSource])) as ConditionPF2e[]; return items.shift() ?? null; } @@ -1567,7 +1575,7 @@ class ActorPF2e extends Actor { protected override async _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { // Set default portrait and token images @@ -1582,7 +1590,7 @@ class ActorPF2e extends Actor { protected override async _preUpdate( changed: DeepPartial, - options: ActorUpdateContext, + options: ActorUpdateContext, user: UserPF2e ): Promise { // Show floaty text when applying damage or healing @@ -1599,14 +1607,14 @@ class ActorPF2e extends Actor { protected override _onUpdate( changed: DeepPartial, - options: ActorUpdateContext, + options: ActorUpdateContext, userId: string ): void { super._onUpdate(changed, options, userId); const hideFromUser = !this.hasPlayerOwner && !game.user.isGM && game.settings.get("pf2e", "metagame_secretDamage"); if (options.damageTaken && !hideFromUser) { - const tokens = super.getActiveTokens(); + const tokens = this.getActiveTokens(); for (const token of tokens) { token.showFloatyText(options.damageTaken); } @@ -1621,7 +1629,7 @@ class ActorPF2e extends Actor { } /** Unregister all effects possessed by this actor */ - protected override _onDelete(options: DocumentModificationContext, userId: string): void { + protected override _onDelete(options: DocumentModificationContext, userId: string): void { for (const effect of this.itemTypes.effect) { game.pf2e.effectTracker.unregister(effect); } @@ -1647,69 +1655,67 @@ class ActorPF2e extends Actor { } } -interface ActorPF2e extends Actor { +interface ActorPF2e extends Actor { flags: ActorFlagsPF2e; readonly _source: ActorSourcePF2e; - readonly effects: foundry.abstract.EmbeddedCollection; - readonly items: foundry.abstract.EmbeddedCollection; + readonly effects: foundry.abstract.EmbeddedCollection>; + readonly items: foundry.abstract.EmbeddedCollection>; system: ActorSystemData; prototypeToken: PrototypeTokenPF2e; - _sheet: ActorSheetPF2e | ActorSheet | null; - get sheet(): ActorSheetPF2e; /** See implementation in class */ createEmbeddedDocuments( embeddedName: "ActiveEffect", - data: PreCreate[], - context?: DocumentModificationContext - ): Promise; + data: PreCreate[], + context?: DocumentModificationContext + ): Promise[]>; createEmbeddedDocuments( embeddedName: "Item", data: PreCreate[], - context?: DocumentModificationContext - ): Promise; + context?: DocumentModificationContext + ): Promise[]>; createEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - data: PreCreate[] | PreCreate[], - context?: DocumentModificationContext - ): Promise; + data: PreCreate[] | PreCreate[], + context?: DocumentModificationContext + ): Promise[] | ItemPF2e[]>; /** See implementation in class */ updateEmbeddedDocuments( embeddedName: "ActiveEffect", - updateData: EmbeddedDocumentUpdateData[], - options?: DocumentModificationContext - ): Promise; + updateData: EmbeddedDocumentUpdateData>[], + options?: DocumentUpdateContext + ): Promise[]>; updateEmbeddedDocuments( embeddedName: "Item", - updateData: EmbeddedDocumentUpdateData[], - options?: DocumentModificationContext - ): Promise; + updateData: EmbeddedDocumentUpdateData>[], + options?: DocumentUpdateContext + ): Promise[]>; updateEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - updateData: EmbeddedDocumentUpdateData[], - options?: DocumentModificationContext - ): Promise; + updateData: EmbeddedDocumentUpdateData | ItemPF2e>[], + options?: DocumentUpdateContext + ): Promise[] | ItemPF2e[]>; - getCondition(conditionType: ConditionKey, { all }: { all: true }): Embedded[]; - getCondition(conditionType: ConditionKey, { all }: { all: false }): Embedded | null; - getCondition(conditionType: ConditionKey): Embedded | null; + getCondition(conditionType: ConditionKey, { all }: { all: true }): ConditionPF2e[]; + getCondition(conditionType: ConditionKey, { all }: { all: false }): ConditionPF2e | null; + getCondition(conditionType: ConditionKey): ConditionPF2e | null; getCondition( conditionType: ConditionKey, { all }: { all: boolean } - ): Embedded[] | Embedded | null; + ): ConditionPF2e[] | ConditionPF2e | null; + + getActiveTokens(linked: boolean | undefined, document: true): TokenDocumentPF2e[]; + getActiveTokens(linked?: undefined, document?: undefined): TokenPF2e[]; + getActiveTokens(linked?: boolean, document?: boolean): TokenDocumentPF2e[] | TokenPF2e[]; /** Added as debounced method */ checkAreaEffects(): void; } -type ItemTypeMap = { - [K in ItemType]: InstanceType; -}; - interface HitPointsSummary { value: number; max: number; @@ -1717,7 +1723,7 @@ interface HitPointsSummary { negativeHealing: boolean; } -interface ActorUpdateContext extends DocumentUpdateContext { +interface ActorUpdateContext extends DocumentUpdateContext { damageTaken?: number; } @@ -1725,7 +1731,7 @@ interface ActorUpdateContext extends DocumentUpdateContext< const ActorProxyPF2e = new Proxy(ActorPF2e, { construct( _target, - args: [source: PreCreate, context: DocumentConstructionContext] + args: [source: PreCreate, context?: DocumentConstructionContext] ) { return new CONFIG.PF2E.Actor.documentClasses[args[0].type](...args); }, diff --git a/src/module/actor/character/crafting/entry.ts b/src/module/actor/character/crafting/entry.ts index a05c96656eb..0f75810a113 100644 --- a/src/module/actor/character/crafting/entry.ts +++ b/src/module/actor/character/crafting/entry.ts @@ -18,7 +18,7 @@ class CraftingEntry implements Omit { batchSize?: number; fieldDiscoveryBatchSize?: number; maxItemLevel: number; - parentItem: Embedded; + parentItem: ItemPF2e; constructor(actor: CharacterPF2e, knownFormulas: CraftingFormula[], data: CraftingEntryData) { this.selector = data.selector; diff --git a/src/module/actor/character/crafting/helpers.ts b/src/module/actor/character/crafting/helpers.ts index 52f1912595b..9e477a399ef 100644 --- a/src/module/actor/character/crafting/helpers.ts +++ b/src/module/actor/character/crafting/helpers.ts @@ -116,7 +116,7 @@ export async function craftSpellConsumable( .reduce((result, spell) => { result[spell.baseLevel] = [...(result[spell.baseLevel] || []), spell]; return result; - }, []>>{}); + }, []>>{}); const content = await renderTemplate("systems/pf2e/templates/actors/crafting-select-spell-dialog.hbs", { spells: validSpells, }); diff --git a/src/module/actor/character/data/sheet.ts b/src/module/actor/character/data/sheet.ts index 8fa61db937c..50b25620784 100644 --- a/src/module/actor/character/data/sheet.ts +++ b/src/module/actor/character/data/sheet.ts @@ -64,14 +64,14 @@ interface CraftingSheetData { type CharacterSheetTabVisibility = Record<(typeof CHARACTER_SHEET_TABS)[number], boolean>; -interface CharacterSheetData extends CreatureSheetData { +interface CharacterSheetData extends CreatureSheetData { abpEnabled: boolean; - ancestry: Embedded | null; - heritage: Embedded | null; - background: Embedded | null; + ancestry: AncestryPF2e | null; + heritage: HeritagePF2e | null; + background: BackgroundPF2e | null; adjustedBonusEncumbranceBulk: boolean; adjustedBonusLimitBulk: boolean; - class: Embedded | null; + class: ClassPF2e | null; classDCs: { dcs: ClassDCSheetData[]; /** The slug of the character's primary class DC */ @@ -81,7 +81,7 @@ interface CharacterSheetData extends CreatureSheetData { }; crafting: CraftingSheetData; data: CharacterSystemSheetData; - deity: Embedded | null; + deity: DeityPF2e | null; hasStamina: boolean; /** This actor has actual containers for stowing, rather than just containers serving as a UI convenience */ hasRealContainers: boolean; diff --git a/src/module/actor/character/data/types.ts b/src/module/actor/character/data/types.ts index 80bfda98e36..20f5df68b5f 100644 --- a/src/module/actor/character/data/types.ts +++ b/src/module/actor/character/data/types.ts @@ -37,6 +37,7 @@ import { ZeroToFour } from "@module/data"; import { PredicatePF2e } from "@system/predication"; import { StatisticTraceData } from "@system/statistic"; import { CharacterSheetTabVisibility } from "./sheet"; +import { CharacterPF2e } from ".."; interface CharacterSource extends BaseCreatureSource<"character", CharacterSystemData> { flags: DeepPartial; @@ -231,7 +232,7 @@ interface ClassDCData extends Required, StatisticTraceDat /** The full data for a character strike */ interface CharacterStrike extends StrikeData { - item: Embedded; + item: WeaponPF2e; /** Whether this attack is visible on the sheet */ visible: boolean; altUsages: CharacterStrike[]; diff --git a/src/module/actor/character/document.ts b/src/module/actor/character/document.ts index ea658dd59b6..e34aff3ab8e 100644 --- a/src/module/actor/character/document.ts +++ b/src/module/actor/character/document.ts @@ -2,16 +2,17 @@ import { CreaturePF2e, FamiliarPF2e } from "@actor"; import { Abilities, CreatureSpeeds, LabeledSpeed, MovementType, SkillAbbreviation } from "@actor/creature/data"; import { CreatureUpdateContext } from "@actor/creature/types"; import { ALLIANCES } from "@actor/creature/values"; +import { StrikeData } from "@actor/data/base"; import { ActorSizePF2e } from "@actor/data/size"; import { calculateMAPs } from "@actor/helpers"; import { CheckModifier, + MODIFIER_TYPE, + ModifierPF2e, + StatisticModifier, createAbilityModifier, createProficiencyModifier, ensureProficiencyOption, - ModifierPF2e, - MODIFIER_TYPE, - StatisticModifier, } from "@actor/modifiers"; import { AbilityString, @@ -63,6 +64,7 @@ import { extractRollTwice, } from "@module/rules/helpers"; import { UserPF2e } from "@module/user"; +import { TokenDocumentPF2e } from "@scene"; import { eventToRollParams } from "@scripts/sheet-util"; import { CheckPF2e, CheckRoll, CheckRollContext } from "@system/check"; import { DamagePF2e, DamageRollContext } from "@system/damage"; @@ -83,8 +85,8 @@ import { CharacterProficiency, CharacterSaves, CharacterSkillData, - CharacterStrike, CharacterSource, + CharacterStrike, CharacterSystemData, ClassDCData, LinkedProficiency, @@ -95,25 +97,24 @@ import { } from "./data"; import { CharacterSheetTabVisibility } from "./data/sheet"; import { CharacterFeats } from "./feats"; -import { createForceOpenPenalty, createShoddyPenalty, StrikeWeaponTraits } from "./helpers"; +import { StrikeWeaponTraits, createForceOpenPenalty, createShoddyPenalty } from "./helpers"; import { CharacterHitPointsSummary, CharacterSkills, CreateAuxiliaryParams, DexterityModifierCapData } from "./types"; import { CHARACTER_SHEET_TABS } from "./values"; -import { StrikeData } from "@actor/data/base"; -class CharacterPF2e extends CreaturePF2e { +class CharacterPF2e extends CreaturePF2e { /** Core singular embeds for PCs */ - ancestry!: Embedded | null; - heritage!: Embedded | null; - background!: Embedded | null; - class!: Embedded | null; - deity!: Embedded | null; + ancestry!: AncestryPF2e | null; + heritage!: HeritagePF2e | null; + background!: BackgroundPF2e | null; + class!: ClassPF2e | null; + deity!: DeityPF2e | null; /** A cached reference to this PC's familiar */ familiar: FamiliarPF2e | null = null; - feats!: CharacterFeats; - pfsBoons!: FeatPF2e[]; - deityBoonsCurses!: FeatPF2e[]; + feats!: CharacterFeats; + pfsBoons!: FeatPF2e[]; + deityBoonsCurses!: FeatPF2e[]; /** All base casting tradition proficiences, which spellcasting build off of */ traditions!: Record; @@ -182,7 +183,7 @@ class CharacterPF2e extends CreaturePF2e { if (!items.every((i): i is ItemPF2e => i instanceof ItemPF2e)) return []; return items - .filter((item): item is PhysicalItemPF2e => item instanceof PhysicalItemPF2e) + .filter((i): i is PhysicalItemPF2e => i.isOfType("physical")) .map((item) => { const { dc, batchSize, deletable } = formulaMap.get(item.uuid) ?? { deletable: false }; return new CraftingFormula(item, { dc, batchSize, deletable }); @@ -1350,7 +1351,7 @@ class CharacterPF2e extends CreaturePF2e { // Add a basic unarmed strike const basicUnarmed = includeBasicUnarmed - ? ((): Embedded => { + ? ((): WeaponPF2e => { const source: PreCreate & { system: { damage?: Partial } } = { _id: "xxPF2ExUNARMEDxx", name: game.i18n.localize("PF2E.WeaponTypeUnarmed"), @@ -1375,7 +1376,7 @@ class CharacterPF2e extends CreaturePF2e { }; // No handwraps, so generate straight from source - return new WeaponPF2e(source, { parent: this, pf2e: { ready: true } }) as Embedded; + return new WeaponPF2e(source, { parent: this }); })() : null; @@ -1401,7 +1402,7 @@ class CharacterPF2e extends CreaturePF2e { itemTypes.weapon.filter((w) => w.slug !== handwrapsSlug), Array.from(synthetics.strikes.values()), basicUnarmed ?? [], - ].flat(); + ].flat() as WeaponPF2e[]; // Sort alphabetically, force basic unarmed attack to end, and finally move all readied strikes to beginning return weapons @@ -1418,10 +1419,10 @@ class CharacterPF2e extends CreaturePF2e { /** Prepare a strike action from a weapon */ private prepareStrike( - weapon: Embedded, + weapon: WeaponPF2e, options: { categories: WeaponCategory[]; - ammos?: Embedded[]; + ammos?: ConsumablePF2e[]; defaultAbility?: AbilityString; } ): CharacterStrike { @@ -1931,7 +1932,7 @@ class CharacterPF2e extends CreaturePF2e { return context; } - consumeAmmo(weapon: WeaponPF2e, params: RollParameters): boolean { + consumeAmmo(weapon: WeaponPF2e, params: RollParameters): boolean { const ammo = weapon.ammo; if (!ammo) { return true; @@ -2020,7 +2021,7 @@ class CharacterPF2e extends CreaturePF2e { protected override async _preUpdate( changed: DeepPartial, - options: CreatureUpdateContext, + options: CreatureUpdateContext, user: UserPF2e ): Promise { const systemData = this.system; @@ -2078,11 +2079,13 @@ class CharacterPF2e extends CreaturePF2e { if (actorClass && newLevel !== this.level) { const current = this.itemTypes.feat.filter((feat) => feat.featType === "classfeature"); if (newLevel > this.level) { - const classFeaturesToCreate = (await actorClass.createGrantedItems({ level: newLevel })).filter( - (feature) => - feature.system.level.value > this.level && - !current.some((currentFeature) => currentFeature.sourceId === feature.flags.core?.sourceId) - ); + const classFeaturesToCreate = (await actorClass.createGrantedItems({ level: newLevel })) + .filter( + (feature) => + feature.system.level.value > this.level && + !current.some((currentFeature) => currentFeature.sourceId === feature.flags.core?.sourceId) + ) + .map((i) => i.toObject()); await this.createEmbeddedDocuments("Item", classFeaturesToCreate, { keepId: true, render: false }); } else if (newLevel < this.level) { const classFeaturestoDelete = current.filter((feat) => feat.level > newLevel).map((feat) => feat.id); @@ -2129,7 +2132,8 @@ class CharacterPF2e extends CreaturePF2e { } } -interface CharacterPF2e extends CreaturePF2e { +interface CharacterPF2e + extends CreaturePF2e { flags: CharacterFlags; readonly _source: CharacterSource; system: CharacterSystemData; diff --git a/src/module/actor/character/feats.ts b/src/module/actor/character/feats.ts index fde016c6abe..d573ca91528 100644 --- a/src/module/actor/character/feats.ts +++ b/src/module/actor/character/feats.ts @@ -16,11 +16,11 @@ interface FeatCategoryOptions { level?: number; } -class CharacterFeats extends Collection { +class CharacterFeats extends Collection { /** Feats with no actual category ("bonus feats" in rules text) */ unorganized: BonusFeat[] = []; - constructor(private actor: CharacterPF2e) { + constructor(private actor: TActor) { super(); const classFeatSlots = actor.class?.grantedFeatSlots; @@ -129,7 +129,7 @@ class CharacterFeats extends Collection { } /** Inserts a feat into the character. If category is empty string, its a bonus feat */ - async insertFeat(feat: FeatPF2e, options: { categoryId: string; slotId?: string }): Promise { + async insertFeat(feat: FeatPF2e, options: { categoryId: string; slotId?: string }): Promise[]> { const { category, slotId } = this.get(options.categoryId)?.isFeatValid(feat) ? { category: this.get(options.categoryId), @@ -160,7 +160,7 @@ class CharacterFeats extends Collection { return this.actor.updateEmbeddedDocuments("Item", [{ _id: feat.id, "system.location": null }]); } - const changed: ItemPF2e[] = []; + const changed: ItemPF2e[] = []; // If this is a new feat, create a new feat item on the actor first if (!alreadyHasFeat && (isFeatValidInSlot || !location)) { @@ -257,7 +257,7 @@ class CharacterFeats extends Collection { } } -interface CharacterFeats { +interface CharacterFeats extends Collection { get(key: "ancestryfeature"): FeatCategory; get(key: "classfeature"): FeatCategory; get(key: "ancestry"): FeatCategory; diff --git a/src/module/actor/character/sheet.ts b/src/module/actor/character/sheet.ts index f518716c1d7..2df4eef61b5 100644 --- a/src/module/actor/character/sheet.ts +++ b/src/module/actor/character/sheet.ts @@ -35,7 +35,7 @@ import { CharacterProficiency, CharacterSkillData, CharacterStrike, MartialProfi import { CharacterSheetData, ClassDCSheetData, CraftingEntriesSheetData, FeatCategorySheetData } from "./data/sheet"; import { PCSheetTabManager } from "./tab-manager"; -class CharacterSheetPF2e extends CreatureSheetPF2e { +class CharacterSheetPF2e extends CreatureSheetPF2e { protected readonly actorConfigClass = CharacterConfig; /** A cache of this PC's known formulas, for use by sheet callbacks */ @@ -62,8 +62,8 @@ class CharacterSheetPF2e extends CreatureSheetPF2e { return `systems/pf2e/templates/actors/character/${template}.hbs`; } - override async getData(options?: ActorSheetOptions): Promise { - const sheetData = (await super.getData(options)) as CharacterSheetData; + override async getData(options?: ActorSheetOptions): Promise> { + const sheetData = (await super.getData(options)) as CharacterSheetData; // Martial Proficiencies const proficiencies = Object.entries(sheetData.data.martial); @@ -165,7 +165,7 @@ class CharacterSheetPF2e extends CreatureSheetPF2e { // Is the stamina variant rule enabled? sheetData.hasStamina = game.settings.get("pf2e", "staminaVariant") > 0; sheetData.spellcastingEntries = await this.prepareSpellcasting(); - sheetData.feats = this.prepareFeats(); + sheetData.feats = this.#prepareFeats(); const formulasByLevel = await this.prepareCraftingFormulas(); const flags = this.actor.flags.pf2e; @@ -278,7 +278,7 @@ class CharacterSheetPF2e extends CreatureSheetPF2e { }; // Skills - const lores: LorePF2e[] = []; + const lores: LorePF2e[] = []; for (const itemData of sheetData.items) { const item = this.actor.items.get(itemData._id, { strict: true }); @@ -362,7 +362,7 @@ class CharacterSheetPF2e extends CreatureSheetPF2e { return craftingEntries; } - private prepareFeats(): FeatCategorySheetData[] { + #prepareFeats(): FeatCategorySheetData[] { const unorganized: FeatCategorySheetData = { id: "bonus", label: "PF2E.FeatBonusHeader", @@ -1003,7 +1003,10 @@ class CharacterSheetPF2e extends CreatureSheetPF2e { return typeof categoryId === "string" ? { slotId, categoryId: categoryId } : null; } - protected override async _onDropItem(event: ElementDragEvent, data: DropCanvasItemDataPF2e): Promise { + protected override async _onDropItem( + event: ElementDragEvent, + data: DropCanvasItemDataPF2e + ): Promise[]> { const item = await ItemPF2e.fromDropData(data); if (!item) throw ErrorPF2e("Unable to create item from drop data!"); const actor = this.actor; @@ -1132,8 +1135,11 @@ class CharacterSheetPF2e extends CreatureSheetPF2e { } /** Handle a drop event for an existing Owned Item to sort that item */ - protected override async _onSortItem(event: ElementDragEvent, itemData: ItemSourcePF2e): Promise { - const item = this.actor.items.get(itemData._id); + protected override async _onSortItem( + event: ElementDragEvent, + itemSource: ItemSourcePF2e + ): Promise[]> { + const item = this.actor.items.get(itemSource._id); if (item?.isOfType("feat")) { const featSlot = this.#getNearestFeatSlotId(event); if (!featSlot) return []; @@ -1147,7 +1153,7 @@ class CharacterSheetPF2e extends CreatureSheetPF2e { } } - return super._onSortItem(event, itemData); + return super._onSortItem(event, itemSource); } /** Get the font-awesome icon used to display hero points */ @@ -1162,7 +1168,7 @@ class CharacterSheetPF2e extends CreatureSheetPF2e { } } -interface CharacterSheetPF2e extends CreatureSheetPF2e { +interface CharacterSheetPF2e extends CreatureSheetPF2e { getStrikeFromDOM(target: HTMLElement): CharacterStrike | null; } diff --git a/src/module/actor/character/types.ts b/src/module/actor/character/types.ts index 469f58c2ec3..5310bd8d98b 100644 --- a/src/module/actor/character/types.ts +++ b/src/module/actor/character/types.ts @@ -4,6 +4,7 @@ import { AbilityString, SkillLongForm } from "@actor/types"; import { WeaponPF2e } from "@item"; import { ZeroToFour } from "@module/data"; import { Statistic } from "@system/statistic"; +import { CharacterPF2e } from "."; interface CharacterHitPointsSummary extends HitPointsSummary { recoveryMultiplier: number; @@ -17,14 +18,14 @@ type CharacterSkills = Record & Partial>; interface CreateAuxiliaryInteractParams { - weapon: Embedded; + weapon: WeaponPF2e; action: "Interact"; purpose: "Grip" | "Sheathe" | "Draw" | "Retrieve" | "PickUp"; hands?: 0 | 1 | 2; } interface CreateAuxiliaryReleaseParams { - weapon: Embedded; + weapon: WeaponPF2e; action: "Release"; purpose: "Grip" | "Drop"; hands: 0 | 1; diff --git a/src/module/actor/creature/document.ts b/src/module/actor/creature/document.ts index 9d0e78a1e56..44a9268cd67 100644 --- a/src/module/actor/creature/document.ts +++ b/src/module/actor/creature/document.ts @@ -4,12 +4,12 @@ import { CreatureSource } from "@actor/data"; import { StrikeData } from "@actor/data/base"; import { CheckModifier, - ensureProficiencyOption, - ModifierPF2e, MODIFIER_TYPE, MODIFIER_TYPES, + ModifierPF2e, RawModifier, StatisticModifier, + ensureProficiencyOption, } from "@actor/modifiers"; import { SaveType } from "@actor/types"; import { SKILL_DICTIONARY } from "@actor/values"; @@ -20,7 +20,7 @@ import { EquippedData, ItemCarryType } from "@item/physical/data"; import { isEquipped } from "@item/physical/usage"; import { ActiveEffectPF2e } from "@module/active-effect"; import { Rarity, SIZES, SIZE_SLUGS } from "@module/data"; -import { CombatantPF2e } from "@module/encounter"; +import { CombatantPF2e, EncounterPF2e } from "@module/encounter"; import { RollNotePF2e } from "@module/notes"; import { RuleElementSynthetics } from "@module/rules"; import { @@ -32,6 +32,7 @@ import { import { BaseSpeedSynthetic } from "@module/rules/synthetics"; import { LightLevels } from "@module/scene/data"; import { UserPF2e } from "@module/user"; +import { TokenDocumentPF2e } from "@scene"; import { CheckPF2e, CheckRoll, CheckRollContext } from "@system/check"; import { DamageType } from "@system/damage/types"; import { DAMAGE_CATEGORIES_UNIQUE } from "@system/damage/values"; @@ -66,7 +67,9 @@ import { import { SIZE_TO_REACH } from "./values"; /** An "actor" in a Pathfinder sense rather than a Foundry one: all should contain attributes and abilities */ -abstract class CreaturePF2e extends ActorPF2e { +abstract class CreaturePF2e< + TParent extends TokenDocumentPF2e | null = TokenDocumentPF2e | null +> extends ActorPF2e { // Internal cached value for creature skills protected _skills: CreatureSkills | null = null; @@ -224,12 +227,12 @@ abstract class CreaturePF2e extends ActorPF2e { return Statistic.from(this, stat, "perception", "PF2E.PerceptionCheck", "perception-check"); } - get wornArmor(): Embedded | null { + get wornArmor(): ArmorPF2e | null { return this.itemTypes.armor.find((armor) => armor.isEquipped && armor.isArmor) ?? null; } /** Get the held shield of most use to the wielder */ - override get heldShield(): Embedded | null { + override get heldShield(): ArmorPF2e | null { const heldShields = this.itemTypes.armor.filter((armor) => armor.isEquipped && armor.isShield); return heldShields.length === 0 ? null @@ -396,7 +399,7 @@ abstract class CreaturePF2e extends ActorPF2e { if (this.isFlatFooted({ dueTo: "flanking" })) { const name = game.i18n.localize("PF2E.Item.Condition.Flanked"); const condition = game.pf2e.ConditionManager.getCondition("flat-footed", { name }); - const flatFooted = new ConditionPF2e(condition.toObject(), { parent: this }) as Embedded; + const flatFooted = new ConditionPF2e(condition.toObject(), { parent: this }); const rule = flatFooted.prepareRuleElements().shift(); if (!rule) throw ErrorPF2e("Unexpected error retrieving condition"); @@ -460,7 +463,7 @@ abstract class CreaturePF2e extends ActorPF2e { } // Get or create the combatant - const combatant = await (async (): Promise | null> => { + const combatant = await (async (): Promise | null> => { if (!game.combat) { ui.notifications.error(game.i18n.localize("PF2E.Encounter.NoActiveEncounter")); return null; @@ -564,7 +567,7 @@ abstract class CreaturePF2e extends ActorPF2e { * @param inSlot Whether the item is in the slot or not. Equivilent to "equipped" previously */ async adjustCarryType( - item: Embedded, + item: PhysicalItemPF2e, carryType: ItemCarryType, handsHeld = 0, inSlot = false @@ -811,25 +814,23 @@ abstract class CreaturePF2e extends ActorPF2e { /* -------------------------------------------- */ /** Remove any features linked to a to-be-deleted ABC item */ - override async deleteEmbeddedDocuments( + override deleteEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", ids: string[], - context: DocumentModificationContext = {} - ): Promise { + context?: DocumentModificationContext + ): Promise[] | CollectionValue[]> { if (embeddedName === "Item") { const items = ids.map((id) => this.items.get(id)); const linked = items.flatMap((item) => item?.getLinkedItems?.() ?? []); ids.push(...linked.map((item) => item.id)); } - return super.deleteEmbeddedDocuments(embeddedName, [...new Set(ids)], context) as Promise< - ActiveEffectPF2e[] | ItemPF2e[] - >; + return super.deleteEmbeddedDocuments(embeddedName, [...new Set(ids)], context); } protected override async _preUpdate( changed: DeepPartial, - options: CreatureUpdateContext, + options: CreatureUpdateContext, user: UserPF2e ): Promise { // Clamp hit points @@ -857,7 +858,7 @@ abstract class CreaturePF2e extends ActorPF2e { } } -interface CreaturePF2e extends ActorPF2e { +interface CreaturePF2e extends ActorPF2e { readonly _source: CreatureSource; system: CreatureSystemData; @@ -869,40 +870,40 @@ interface CreaturePF2e extends ActorPF2e { get hitPoints(): HitPointsSummary; /** Expand DocumentModificationContext for creatures */ - update(data: DocumentUpdateData, options?: CreatureUpdateContext): Promise; + update(data: DocumentUpdateData, options?: CreatureUpdateContext): Promise; /** See implementation in class */ updateEmbeddedDocuments( embeddedName: "ActiveEffect", - updateData: EmbeddedDocumentUpdateData[], - options?: DocumentModificationContext - ): Promise; + updateData: EmbeddedDocumentUpdateData>[], + options?: DocumentUpdateContext + ): Promise[]>; updateEmbeddedDocuments( embeddedName: "Item", - updateData: EmbeddedDocumentUpdateData[], - options?: DocumentModificationContext - ): Promise; + updateData: EmbeddedDocumentUpdateData>[], + options?: DocumentUpdateContext + ): Promise[]>; updateEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - updateData: EmbeddedDocumentUpdateData[], - options?: DocumentModificationContext - ): Promise; + updateData: EmbeddedDocumentUpdateData | ItemPF2e>[], + options?: DocumentUpdateContext + ): Promise[] | ItemPF2e[]>; deleteEmbeddedDocuments( embeddedName: "ActiveEffect", - dataId: string[], - context?: DocumentModificationContext - ): Promise; + ids: string[], + context?: DocumentModificationContext + ): Promise[]>; deleteEmbeddedDocuments( embeddedName: "Item", - dataId: string[], - context?: DocumentModificationContext - ): Promise; + ids: string[], + context?: DocumentModificationContext + ): Promise[]>; deleteEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - dataId: string[], - context?: DocumentModificationContext - ): Promise; + ids: string[], + context?: DocumentModificationContext + ): Promise[] | CollectionValue[]>; } export { CreaturePF2e }; diff --git a/src/module/actor/creature/sheet.ts b/src/module/actor/creature/sheet.ts index 15cdac0fc2a..f6ad892ac71 100644 --- a/src/module/actor/creature/sheet.ts +++ b/src/module/actor/creature/sheet.ts @@ -274,8 +274,10 @@ export abstract class CreatureSheetPF2e extends Act for (const element of htmlQueryAll(section, "[data-action=spellcasting-edit]") ?? []) { element.addEventListener("click", (event) => { const containerId = htmlClosest(event.target, "[data-item-id]")?.dataset.itemId; - const entry = this.actor.spellcasting.get(containerId, { strict: true }); - createSpellcastingDialog(event, entry as Embedded); + const entry = this.actor.items.get(containerId, { strict: true }); + if (entry.isOfType("spellcastingEntry")) { + createSpellcastingDialog(event, entry); + } }); } @@ -379,7 +381,10 @@ export abstract class CreatureSheetPF2e extends Act } /** Adds support for moving spells between spell levels, spell collections, and spell preparation */ - protected override async _onSortItem(event: ElementDragEvent, itemSource: ItemSourcePF2e): Promise { + protected override async _onSortItem( + event: ElementDragEvent, + itemSource: ItemSourcePF2e + ): Promise[]> { const dropItemEl = htmlClosest(event.target, ".item"); const dropContainerEl = htmlClosest(event.target, ".item-container"); @@ -406,7 +411,7 @@ export abstract class CreatureSheetPF2e extends Act if (Number.isInteger(dropId) && Number.isInteger(slotLevel)) { const allocated = await collection.prepareSpell(item, slotLevel, dropId); - if (allocated) return [allocated]; + if (allocated instanceof SpellcastingEntryPF2e) return [allocated]; } } else if (dropSlotType === "spell") { const dropId = dropItemEl.dataset.itemId ?? ""; @@ -467,9 +472,9 @@ export abstract class CreatureSheetPF2e extends Act /** Handle dragging spells onto spell slots. */ protected override async _handleDroppedItem( event: ElementDragEvent, - item: ItemPF2e, + item: ItemPF2e, data: DropCanvasItemDataPF2e - ): Promise { + ): Promise[]> { const containerEl = htmlClosest(event.target, ".item-container[data-container-type=spellcastingEntry]"); if (containerEl && item.isOfType("spell") && !item.isRitual) { const entryId = containerEl.dataset.containerId; diff --git a/src/module/actor/creature/spell-preparation-sheet.ts b/src/module/actor/creature/spell-preparation-sheet.ts index 7993d868683..8d68bf1029f 100644 --- a/src/module/actor/creature/spell-preparation-sheet.ts +++ b/src/module/actor/creature/spell-preparation-sheet.ts @@ -1,4 +1,4 @@ -import { ActorPF2e } from "@actor"; +import { ActorPF2e, CreaturePF2e } from "@actor"; import { ItemSummaryRenderer } from "@actor/sheet/item-summary-renderer"; import { ItemPF2e, SpellPF2e } from "@item"; import { ItemSourcePF2e, SpellSource } from "@item/data"; @@ -8,11 +8,11 @@ import { SpellcastingSheetData, SpellcastingEntryPF2e } from "@item/spellcasting * Sheet used to render the the spell list for prepared casting. * It overrides the actor sheet to inherit important drag/drop behavior for actor items (the spells). */ -class SpellPreparationSheet extends ActorSheet { +class SpellPreparationSheet extends ActorSheet { /** Implementation used to handle the toggling and rendering of item summaries */ - itemRenderer: ItemSummaryRenderer = new ItemSummaryRenderer(this); + itemRenderer: ItemSummaryRenderer = new ItemSummaryRenderer(this); - constructor(public item: Embedded, options: Partial) { + constructor(public item: SpellcastingEntryPF2e, options: Partial) { super(item.actor, options); } @@ -52,7 +52,7 @@ class SpellPreparationSheet extends ActorSheet { return buttons; } - override async getData(): Promise { + override async getData(): Promise> { return { ...(await super.getData()), owner: this.actor.isOwner, @@ -111,14 +111,17 @@ class SpellPreparationSheet extends ActorSheet { }); } - private getItemFromEvent(event: JQuery.TriggeredEvent): Embedded { + private getItemFromEvent(event: JQuery.TriggeredEvent): ItemPF2e { const $li = $(event.currentTarget).closest("li[data-item-id]"); const itemId = $li.attr("data-item-id") ?? ""; return this.actor.items.get(itemId, { strict: true }); } /** Allow adding new spells to the shortlist by dragging directly into the window */ - protected override async _onDropItemCreate(itemSource: ItemSourcePF2e | ItemSourcePF2e[]): Promise { + protected override async _onDropItemCreate( + itemSource: ItemSourcePF2e | ItemSourcePF2e[] + ): Promise[]>; + protected override async _onDropItemCreate(itemSource: ItemSourcePF2e | ItemSourcePF2e[]): Promise[]> { const sources = Array.isArray(itemSource) ? itemSource : [itemSource]; const spellSources = sources.filter((source): source is SpellSource => source.type === "spell"); for (const spellSource of spellSources) { @@ -129,7 +132,11 @@ class SpellPreparationSheet extends ActorSheet { } /** Allow transferring spells between open windows */ - protected override async _onSortItem(event: ElementDragEvent, itemData: ItemSourcePF2e): Promise { + protected override async _onSortItem( + event: ElementDragEvent, + itemData: ItemSourcePF2e + ): Promise[]>; + protected override async _onSortItem(event: ElementDragEvent, itemData: ItemSourcePF2e): Promise[]> { if (itemData.type !== "spell") return []; const spell = this.actor.items.get(itemData._id); @@ -149,8 +156,7 @@ class SpellPreparationSheet extends ActorSheet { } } -interface SpellPreparationSheetData extends ActorSheetData { - actor: ActorPF2e; +interface SpellPreparationSheetData extends ActorSheetData { owner: boolean; entry: SpellcastingSheetData; } diff --git a/src/module/actor/creature/types.ts b/src/module/actor/creature/types.ts index 2e646356780..7a22931ae53 100644 --- a/src/module/actor/creature/types.ts +++ b/src/module/actor/creature/types.ts @@ -1,13 +1,14 @@ +import { ActorPF2e, ActorUpdateContext } from "@actor/base"; import { ActorSheetDataPF2e } from "@actor/sheet/data-types"; +import { AbilityString, SaveType } from "@actor/types"; import { MeleePF2e, WeaponPF2e } from "@item"; -import { CreaturePF2e } from "."; +import { ZeroToFour } from "@module/data"; import { SheetOptions } from "@module/sheet/helpers"; -import { ALIGNMENTS, ALIGNMENT_TRAITS } from "./values"; +import { TokenDocumentPF2e } from "@scene"; import { FlattenedCondition } from "@system/conditions"; -import { ActorUpdateContext } from "@actor/base"; +import { CreaturePF2e } from "."; import { AbilityData, CreatureSystemData, SaveData, SkillData } from "./data"; -import { ZeroToFour } from "@module/data"; -import { AbilityString, SaveType } from "@actor/types"; +import { ALIGNMENTS, ALIGNMENT_TRAITS } from "./values"; type Alignment = SetElement; type AlignmentTrait = SetElement; @@ -17,7 +18,7 @@ type ModeOfBeing = "living" | "undead" | "construct" | "object"; interface GetReachParameters { action?: "interact" | "attack"; - weapon?: WeaponPF2e | MeleePF2e | null; + weapon?: WeaponPF2e | MeleePF2e | null; } interface IsFlatFootedParams { @@ -25,13 +26,13 @@ interface IsFlatFootedParams { dueTo: "flanking" | "surprise" | "hidden" | "undetected"; } -interface CreatureUpdateContext extends ActorUpdateContext { +interface CreatureUpdateContext extends ActorUpdateContext { allowHPOverage?: boolean; } type WithRank = { icon?: string; hover?: string; rank: ZeroToFour }; -interface CreatureSheetData extends ActorSheetDataPF2e { +interface CreatureSheetData extends ActorSheetDataPF2e { data: CreatureSystemData & { abilities: Record; attributes: { diff --git a/src/module/actor/data/base.ts b/src/module/actor/data/base.ts index 3780f068e2a..20114f10820 100644 --- a/src/module/actor/data/base.ts +++ b/src/module/actor/data/base.ts @@ -1,22 +1,23 @@ import { DexterityModifierCapData } from "@actor/character/types"; -import { SkillAbbreviation } from "@actor/creature/data"; +import { Abilities, SkillAbbreviation } from "@actor/creature/data"; import { ActorSizePF2e } from "@actor/data/size"; import { StatisticModifier } from "@actor/modifiers"; import { AbilityString, ActorAlliance } from "@actor/types"; import { ConsumablePF2e, MeleePF2e, WeaponPF2e } from "@item"; import { ItemSourcePF2e } from "@item/data"; import { DocumentSchemaRecord, Rarity, Size, ValueAndMaybeMax, ZeroToTwo } from "@module/data"; -import { CombatantPF2e } from "@module/encounter"; +import { CombatantPF2e, EncounterPF2e } from "@module/encounter"; import { AutoChangeEntry } from "@module/rules/rule-element/ae-like"; import { RollParameters, AttackRollParams, DamageRollParams } from "@module/system/rolls"; import { CheckRoll } from "@system/check"; import { DamageRoll } from "@system/damage/roll"; import { ActorType } from "."; import { ImmunityData, ImmunitySource, ResistanceData, ResistanceSource, WeaknessData, WeaknessSource } from "./iwr"; +import { ActorPF2e } from "@actor/base"; /** Base interface for all actor data */ interface BaseActorSourcePF2e - extends foundry.data.ActorSource { + extends foundry.documents.ActorSource { flags: DeepPartial; prototypeToken: PrototypeTokenSourcePF2e; } @@ -61,6 +62,7 @@ interface ActorDetailsSource { } interface ActorSystemData extends ActorSystemSource { + abilities?: Abilities; details: ActorDetails; actions?: StrikeData[]; attributes: ActorAttributes; @@ -182,7 +184,7 @@ interface InitiativeData { } interface InitiativeRollResult { - combatant: CombatantPF2e; + combatant: CombatantPF2e; roll: Rolled; } @@ -269,7 +271,7 @@ interface StrikeData extends StatisticModifier { }; /** The weapon or melee item--possibly ephemeral--being used for the strike */ - item: WeaponPF2e | MeleePF2e; + item: WeaponPF2e | MeleePF2e; } /** Any skill or similar which provides a roll option for rolling this save. */ diff --git a/src/module/actor/familiar/document.ts b/src/module/actor/familiar/document.ts index 76ec838b8ae..44ec485edee 100644 --- a/src/module/actor/familiar/document.ts +++ b/src/module/actor/familiar/document.ts @@ -1,16 +1,17 @@ import { CharacterPF2e, CreaturePF2e } from "@actor"; import { CreatureSaves, LabeledSpeed } from "@actor/creature/data"; import { ActorSizePF2e } from "@actor/data/size"; -import { applyStackingRules, CheckModifier, ModifierPF2e, MODIFIER_TYPE, StatisticModifier } from "@actor/modifiers"; +import { CheckModifier, MODIFIER_TYPE, ModifierPF2e, StatisticModifier, applyStackingRules } from "@actor/modifiers"; import { SaveType } from "@actor/types"; import { SAVE_TYPES, SKILL_ABBREVIATIONS, SKILL_DICTIONARY, SKILL_EXPANDED } from "@actor/values"; import { extractDegreeOfSuccessAdjustments, extractModifiers, extractRollTwice } from "@module/rules/helpers"; +import { TokenDocumentPF2e } from "@scene"; import { CheckPF2e, CheckRoll } from "@system/check"; import { RollParameters } from "@system/rolls"; import { Statistic } from "@system/statistic"; import { FamiliarSource, FamiliarSystemData } from "./data"; -class FamiliarPF2e extends CreaturePF2e { +class FamiliarPF2e extends CreaturePF2e { /** The familiar's master, if selected */ get master(): CharacterPF2e | null { // The Actors world collection needs to be initialized for data preparation @@ -352,13 +353,14 @@ class FamiliarPF2e extends CreaturePF2e { /* -------------------------------------------- */ /** Remove the master's reference to this familiar */ - protected override _onDelete(options: DocumentModificationContext, userId: string): void { + protected override _onDelete(options: DocumentModificationContext, userId: string): void { if (this.master) this.master.familiar = null; super._onDelete(options, userId); } } -interface FamiliarPF2e extends CreaturePF2e { +interface FamiliarPF2e + extends CreaturePF2e { readonly _source: FamiliarSource; system: FamiliarSystemData; } diff --git a/src/module/actor/familiar/sheet.ts b/src/module/actor/familiar/sheet.ts index 9b37f817acc..6466133afbd 100644 --- a/src/module/actor/familiar/sheet.ts +++ b/src/module/actor/familiar/sheet.ts @@ -6,11 +6,11 @@ import { FamiliarSheetData } from "./types"; /** * @category Actor */ -export class FamiliarSheetPF2e extends CreatureSheetPF2e { +export class FamiliarSheetPF2e extends CreatureSheetPF2e { /** There is currently no actor config for familiars */ protected readonly actorConfigClass = null; - static override get defaultOptions() { + static override get defaultOptions(): ActorSheetOptions { const options = super.defaultOptions; mergeObject(options, { classes: [...options.classes, "familiar"], @@ -25,12 +25,12 @@ export class FamiliarSheetPF2e extends CreatureSheetPF2e { return "systems/pf2e/templates/actors/familiar-sheet.hbs"; } - override async getData(options?: ActorSheetOptions): Promise { + override async getData(options?: ActorSheetOptions): Promise> { const baseData = await super.getData(options); const familiar = this.actor; // Get all potential masters of the familiar const masters = game.actors.filter( - (a): a is CharacterPF2e => a.isOfType("character") && a.testUserPermission(game.user, "OWNER") + (a): a is CharacterPF2e => a.type === "character" && a.testUserPermission(game.user, "OWNER") ); // list of abilities that can be selected as spellcasting ability diff --git a/src/module/actor/familiar/types.ts b/src/module/actor/familiar/types.ts index 812b4209f85..65ba6676a64 100644 --- a/src/module/actor/familiar/types.ts +++ b/src/module/actor/familiar/types.ts @@ -2,7 +2,7 @@ import { CharacterPF2e } from "@actor"; import { CreatureSheetData } from "@actor/creature/types"; import { FamiliarPF2e } from "."; -interface FamiliarSheetData extends CreatureSheetData { +interface FamiliarSheetData extends CreatureSheetData { master: CharacterPF2e | null; masters: CharacterPF2e[]; abilities: ConfigPF2e["PF2E"]["abilities"]; diff --git a/src/module/actor/hazard/document.ts b/src/module/actor/hazard/document.ts index 926ecdbdd43..8be0a6da5c8 100644 --- a/src/module/actor/hazard/document.ts +++ b/src/module/actor/hazard/document.ts @@ -1,18 +1,19 @@ import { ActorPF2e } from "@actor"; import { strikeFromMeleeItem } from "@actor/helpers"; -import { ModifierPF2e, MODIFIER_TYPE, StatisticModifier } from "@actor/modifiers"; +import { MODIFIER_TYPE, ModifierPF2e, StatisticModifier } from "@actor/modifiers"; import { SaveType } from "@actor/types"; import { SAVE_TYPES } from "@actor/values"; import { ConditionPF2e } from "@item"; import { ItemType } from "@item/data"; import { Rarity } from "@module/data"; import { extractModifiers } from "@module/rules/helpers"; +import { TokenDocumentPF2e } from "@scene"; import { DamageType } from "@system/damage"; import { Statistic } from "@system/statistic"; import { isObject, objectHasKey } from "@util"; import { HazardSource, HazardSystemData } from "./data"; -class HazardPF2e extends ActorPF2e { +class HazardPF2e extends ActorPF2e { override get allowedItemTypes(): (ItemType | "physical")[] { return [...super.allowedItemTypes, "action", "melee"]; } @@ -131,7 +132,7 @@ class HazardPF2e extends ActorPF2e { } } -interface HazardPF2e extends ActorPF2e { +interface HazardPF2e extends ActorPF2e { readonly _source: HazardSource; system: HazardSystemData; diff --git a/src/module/actor/helpers.ts b/src/module/actor/helpers.ts index b58dc9f2865..5cd90d12858 100644 --- a/src/module/actor/helpers.ts +++ b/src/module/actor/helpers.ts @@ -1,5 +1,6 @@ import { ActorPF2e, ActorProxyPF2e } from "@actor"; import { ItemPF2e, MeleePF2e } from "@item"; +import { ZeroToTwo } from "@module/data"; import { MigrationList, MigrationRunner } from "@module/migration"; import { MigrationRunnerBase } from "@module/migration/runner/base"; import { @@ -11,6 +12,7 @@ import { extractRollTwice, } from "@module/rules/helpers"; import { TokenDocumentPF2e } from "@scene"; +import { eventToRollParams } from "@scripts/sheet-util"; import { CheckPF2e, CheckRoll } from "@system/check"; import { DamagePF2e, DamageRollContext } from "@system/damage"; import { DamageRoll } from "@system/damage/roll"; @@ -19,13 +21,11 @@ import { AttackRollParams, DamageRollParams } from "@system/rolls"; import { ErrorPF2e, getActionGlyph, getActionIcon, sluggify } from "@util"; import { ActorSourcePF2e } from "./data"; import { DamageRollFunction, TraitViewData } from "./data/base"; -import { CheckModifier, ModifierPF2e, MODIFIER_TYPE, StatisticModifier } from "./modifiers"; +import { CheckModifier, MODIFIER_TYPE, ModifierPF2e, StatisticModifier } from "./modifiers"; import { NPCStrike } from "./npc/data"; import { StrikeAttackTraits } from "./npc/strike-attack-traits"; import { AttackItem } from "./types"; import { ANIMAL_COMPANION_SOURCE_ID, CONSTRUCT_COMPANION_SOURCE_ID } from "./values"; -import { eventToRollParams } from "@scripts/sheet-util"; -import { ZeroToTwo } from "@module/data"; /** Reset and rerender a provided list of actors. Omit argument to reset all world and synthetic actors */ async function resetActors(actors?: Iterable, { rerender = true } = {}): Promise { @@ -147,7 +147,7 @@ function calculateMAPs( } /** Create a strike statistic from a melee item: for use by NPCs and Hazards */ -function strikeFromMeleeItem(item: Embedded): NPCStrike { +function strikeFromMeleeItem(item: MeleePF2e): NPCStrike { const { ability, isMelee, isThrown } = item; const { actor } = item; if (!actor.isOfType("npc", "hazard")) { @@ -191,7 +191,8 @@ function strikeFromMeleeItem(item: Embedded): NPCStrike { const attackEffects: Record = CONFIG.PF2E.attackEffects; const additionalEffects = item.attackEffects.map((tag) => { - const label = attackEffects[tag] ?? actor.items.find((i) => (i.slug ?? sluggify(i.name)) === tag)?.name ?? tag; + const items: ItemPF2e[] = actor.items.contents; + const label = attackEffects[tag] ?? items.find((i) => (i.slug ?? sluggify(i.name)) === tag)?.name ?? tag; return { tag, label }; }); diff --git a/src/module/actor/inventory/index.ts b/src/module/actor/inventory/index.ts index 9749590b66d..ccf60c6a1fb 100644 --- a/src/module/actor/inventory/index.ts +++ b/src/module/actor/inventory/index.ts @@ -6,8 +6,8 @@ import { coinCompendiumIds, CoinsPF2e } from "@item/physical/helpers"; import { ErrorPF2e, groupBy } from "@util"; import { InventoryBulk } from "./bulk"; -class ActorInventory extends Collection> { - constructor(public readonly actor: ActorPF2e, entries?: Embedded[]) { +class ActorInventory extends Collection> { + constructor(public readonly actor: TActor, entries?: PhysicalItemPF2e[]) { super(entries?.map((entry) => [entry.id, entry])); } @@ -23,7 +23,7 @@ class ActorInventory extends Collection> { .reduce((first, second) => first.add(second), new CoinsPF2e()); } - get invested() { + get invested(): { value: number; max: number } | null { if (this.actor.isOfType("character")) { return { value: this.filter((item) => !!item.isInvested).length, @@ -50,7 +50,7 @@ class ActorInventory extends Collection> { await item.update({ "system.quantity": item.quantity + quantity }); } else { const compendiumId = coinCompendiumIds[denomination]; - const pack = game.packs.find>( + const pack = game.packs.find>>( (p) => p.collection === "pf2e.equipment-srd" ); if (!pack) throw ErrorPF2e("Unexpected error retrieving equipment compendium"); diff --git a/src/module/actor/loot/document.ts b/src/module/actor/loot/document.ts index 9fc6c5b575b..9f853b20ac4 100644 --- a/src/module/actor/loot/document.ts +++ b/src/module/actor/loot/document.ts @@ -1,16 +1,16 @@ import { ActorPF2e } from "@actor/base"; -import { PhysicalItemPF2e } from "@item/physical"; import { ItemPF2e } from "@item/base"; -import { ErrorPF2e } from "@util"; -import { UserPF2e } from "@module/user"; -import { LootSource, LootSystemData } from "./data"; -import { ActiveEffectPF2e } from "@module/active-effect"; import { ItemSourcePF2e, ItemType } from "@item/data"; -import { TokenDocumentPF2e } from "@module/scene/token-document"; -import { ScenePF2e } from "@module/scene"; +import { PhysicalItemPF2e } from "@item/physical"; import { CoinsPF2e } from "@item/physical/helpers"; +import { ActiveEffectPF2e } from "@module/active-effect"; +import { ScenePF2e } from "@module/scene"; +import { TokenDocumentPF2e } from "@module/scene/token-document"; +import { UserPF2e } from "@module/user"; +import { ErrorPF2e } from "@util"; +import { LootSource, LootSystemData } from "./data"; -class LootPF2e extends ActorPF2e { +class LootPF2e extends ActorPF2e { override get allowedItemTypes(): (ItemType | "physical")[] { return ["physical"]; } @@ -58,11 +58,11 @@ class LootPF2e extends ActorPF2e { override async transferItemToActor( targetActor: ActorPF2e, - item: Embedded, + item: ItemPF2e, quantity: number, containerId?: string, newStack = false - ): Promise | null> { + ): Promise | null> { // If we don't have permissions send directly to super to prevent removing the coins twice or reject as needed if (!(this.isOwner && targetActor.isOwner)) { return super.transferItemToActor(targetActor, item, quantity, containerId, newStack); @@ -86,9 +86,9 @@ class LootPF2e extends ActorPF2e { async toggleTokenHiding(): Promise { if (!this.hiddenWhenEmpty) return; const hiddenStatus = this.items.size === 0; - const scenesAndTokens: [ScenePF2e, TokenDocumentPF2e[]][] = game.scenes.contents.map((scene) => [ - scene, - scene.tokens.filter((tokenDoc) => tokenDoc.actor === this), + const scenesAndTokens: [ScenePF2e, TokenDocumentPF2e[]][] = game.scenes.map((s) => [ + s, + s.tokens.filter((t) => t.actor === this), ]); const promises = scenesAndTokens.map(([scene, tokenDocs]) => scene.updateEmbeddedDocuments( @@ -109,14 +109,18 @@ class LootPF2e extends ActorPF2e { /* Event Listeners and Handlers */ /* -------------------------------------------- */ - protected override _onCreate(data: LootSource, options: DocumentModificationContext, userId: string): void { + protected override _onCreate( + data: LootSource, + options: DocumentModificationContext, + userId: string + ): void { this.toggleTokenHiding(); super._onCreate(data, options, userId); } protected override _onUpdate( changed: DeepPartial, - options: DocumentUpdateContext, + options: DocumentUpdateContext, userId: string ): void { if (changed.system?.hiddenWhenEmpty !== undefined) { @@ -127,9 +131,9 @@ class LootPF2e extends ActorPF2e { protected override _onCreateEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - documents: ActiveEffectPF2e[] | ItemPF2e[], - result: foundry.data.ActiveEffectSource[] | ItemSourcePF2e[], - options: DocumentModificationContext, + documents: ActiveEffectPF2e[] | ItemPF2e[], + result: foundry.documents.ActiveEffectSource[] | ItemSourcePF2e[], + options: DocumentModificationContext, userId: string ): void { this.toggleTokenHiding(); @@ -138,9 +142,9 @@ class LootPF2e extends ActorPF2e { protected override _onDeleteEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - documents: ActiveEffectPF2e[] | ItemPF2e[], - result: foundry.data.ActiveEffectSource[] | ItemSourcePF2e[], - options: DocumentModificationContext, + documents: ActiveEffectPF2e[] | ItemPF2e[], + result: string[], + options: DocumentModificationContext, userId: string ): void { this.toggleTokenHiding(); @@ -148,7 +152,7 @@ class LootPF2e extends ActorPF2e { } } -interface LootPF2e extends ActorPF2e { +interface LootPF2e extends ActorPF2e { readonly _source: LootSource; system: LootSystemData; diff --git a/src/module/actor/loot/sheet.ts b/src/module/actor/loot/sheet.ts index 582ac80ee0b..cfd809e716e 100644 --- a/src/module/actor/loot/sheet.ts +++ b/src/module/actor/loot/sheet.ts @@ -2,11 +2,11 @@ import { ActorSheetPF2e } from "../sheet/base"; import { LootPF2e } from "@actor/loot"; import { DistributeCoinsPopup } from "../sheet/popups/distribute-coins-popup"; import { LootNPCsPopup } from "../sheet/loot/loot-npcs-popup"; -import { LootSheetDataPF2e } from "../sheet/data-types"; -import { ItemPF2e } from "@item"; import { DropCanvasItemDataPF2e } from "@module/canvas/drop-canvas-data"; +import { ActorSheetDataPF2e } from "@actor/sheet/data-types"; +import { ItemPF2e } from "@item"; -export class LootSheetPF2e extends ActorSheetPF2e { +export class LootSheetPF2e extends ActorSheetPF2e { static override get defaultOptions(): ActorSheetOptions { const options = super.defaultOptions; @@ -28,7 +28,7 @@ export class LootSheetPF2e extends ActorSheetPF2e { return !this.actor.isOwner && this.actor.isLootableBy(game.user); } - override async getData(): Promise { + override async getData(): Promise> { const sheetData = await super.getData(); const isLoot = this.actor.system.lootSheetType === "Loot"; @@ -49,11 +49,11 @@ export class LootSheetPF2e extends ActorSheetPF2e { $html .find(".split-coins") .removeAttr("disabled") - .on("click", (event) => this.distributeCoins(event)); + .on("click", (event) => this.#distributeCoins(event)); $html .find(".loot-npcs") .removeAttr("disabled") - .on("click", (event) => this.lootNPCs(event)); + .on("click", (event) => this.#lootNPCs(event)); $html.find("i.fa-info-circle.help[title]").tooltipster({ maxWidth: 275, position: "right", @@ -63,12 +63,12 @@ export class LootSheetPF2e extends ActorSheetPF2e { } } - private async distributeCoins(event: JQuery.ClickEvent): Promise { + async #distributeCoins(event: JQuery.ClickEvent): Promise { event.preventDefault(); await new DistributeCoinsPopup(this.actor, {}).render(true); } - private async lootNPCs(event: JQuery.ClickEvent): Promise { + async #lootNPCs(event: JQuery.ClickEvent): Promise { event.preventDefault(); if (canvas.tokens.controlled.some((token) => token.actor?.id !== this.actor.id)) { await new LootNPCsPopup(this.actor).render(true); @@ -80,7 +80,7 @@ export class LootSheetPF2e extends ActorSheetPF2e { protected override async _onDropItem( event: ElementDragEvent, itemData: DropCanvasItemDataPF2e - ): Promise { + ): Promise[]> { // Prevent a Foundry permissions error from being thrown when a player drops an item from an unowned // loot sheet to the same sheet if (this.actor.id === itemData.actorId && !this.actor.testUserPermission(game.user, "OWNER")) { @@ -89,3 +89,7 @@ export class LootSheetPF2e extends ActorSheetPF2e { return super._onDropItem(event, itemData); } } + +interface LootSheetDataPF2e extends ActorSheetDataPF2e { + isLoot: boolean; +} diff --git a/src/module/actor/npc/data.ts b/src/module/actor/npc/data.ts index ceb42887178..94f734d758a 100644 --- a/src/module/actor/npc/data.ts +++ b/src/module/actor/npc/data.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor/base"; import { Abilities, BaseCreatureSource, @@ -193,7 +194,7 @@ interface NPCDetails extends NPCDetailsSource { /** The full data for a NPC action (used primarily for strikes.) */ interface NPCStrike extends StrikeData { - item: Embedded; + item: MeleePF2e; /** The type of attack as a localization string */ attackRollType?: string; /** The id of the item this strike is generated from */ diff --git a/src/module/actor/npc/document.ts b/src/module/actor/npc/document.ts index 983eb6fdc96..62458e5119e 100644 --- a/src/module/actor/npc/document.ts +++ b/src/module/actor/npc/document.ts @@ -1,8 +1,8 @@ -import { CreaturePF2e } from "@actor"; +import { ActorPF2e, CreaturePF2e } from "@actor"; import { Abilities } from "@actor/creature/data"; import { SIZE_TO_REACH } from "@actor/creature/values"; import { strikeFromMeleeItem } from "@actor/helpers"; -import { CheckModifier, ModifierPF2e, MODIFIER_TYPE, StatisticModifier } from "@actor/modifiers"; +import { CheckModifier, MODIFIER_TYPE, ModifierPF2e, StatisticModifier } from "@actor/modifiers"; import { SaveType } from "@actor/types"; import { SAVE_TYPES, SKILL_DICTIONARY, SKILL_EXPANDED, SKILL_LONG_FORMS } from "@actor/values"; import { ItemPF2e, MeleePF2e } from "@item"; @@ -17,6 +17,7 @@ import { extractNotes, extractRollTwice, } from "@module/rules/helpers"; +import { TokenDocumentPF2e } from "@scene"; import { CheckPF2e, CheckRoll, CheckRollContext } from "@system/check"; import { LocalizePF2e } from "@system/localize"; import { PredicatePF2e } from "@system/predication"; @@ -27,7 +28,7 @@ import { NPCFlags, NPCSource, NPCSystemData } from "./data"; import { NPCSheetPF2e } from "./sheet"; import { VariantCloneParams } from "./types"; -class NPCPF2e extends CreaturePF2e { +class NPCPF2e extends CreaturePF2e { override get allowedItemTypes(): (ItemType | "physical")[] { return [...super.allowedItemTypes, "physical", "spellcastingEntry", "spell", "action", "melee", "lore"]; } @@ -398,7 +399,7 @@ class NPCPF2e extends CreaturePF2e { // process OwnedItem instances, which for NPCs include skills, attacks, equipment, special abilities etc. const generatedMelee = Array.from(strikes.values()).flatMap((w) => w.toNPCAttacks()); - const items = this.items.contents.concat(generatedMelee); + const items: ItemPF2e[] = [...this.items.contents, ...generatedMelee]; for (const item of items) { if (item.isOfType("lore")) { // override untrained skills if defined in the NPC data @@ -593,13 +594,13 @@ class NPCPF2e extends CreaturePF2e { }) ); } - const formatItemName = (item: ItemPF2e): string => { + const formatItemName = (item: ItemPF2e): string => { if (item.isOfType("consumable")) { return `${item.name} - ${LocalizePF2e.translations.ITEM.TypeConsumable} (${item.quantity}) `; } return item.name; }; - const formatNoteText = (item: ItemPF2e): Promise => { + const formatNoteText = (item: ItemPF2e): Promise => { // Call enrichHTML with the correct item context const rollData = item.getRollData(); return TextEditor.enrichHTML(item.description, { rollData, async: true }); @@ -742,13 +743,11 @@ class NPCPF2e extends CreaturePF2e { } } -interface NPCPF2e extends CreaturePF2e { +interface NPCPF2e extends CreaturePF2e { flags: NPCFlags; readonly _source: NPCSource; system: NPCSystemData; - _sheet: NPCSheetPF2e | null; - get sheet(): NPCSheetPF2e; } diff --git a/src/module/actor/npc/sheet.ts b/src/module/actor/npc/sheet.ts index ca7cba3e7a4..d132f192e11 100644 --- a/src/module/actor/npc/sheet.ts +++ b/src/module/actor/npc/sheet.ts @@ -1,4 +1,4 @@ -import { Abilities, AbilityData } from "@actor/creature/data"; +import { Abilities, AbilityData, SkillAbbreviation } from "@actor/creature/data"; import { CreatureSheetPF2e } from "@actor/creature/sheet"; import { CreatureSheetData } from "@actor/creature/types"; import { ALIGNMENT_TRAITS } from "@actor/creature/values"; @@ -6,7 +6,6 @@ import { NPCPF2e } from "@actor/index"; import { NPCSkillsEditor } from "@actor/npc/skills-editor"; import { AbilityString } from "@actor/types"; import { ABILITY_ABBREVIATIONS, SAVE_TYPES, SKILL_DICTIONARY } from "@actor/values"; -import { ActionItemPF2e, EffectPF2e } from "@item"; import { Size } from "@module/data"; import { createTagifyTraits } from "@module/sheet/helpers"; import { DicePF2e } from "@scripts/dice"; @@ -18,7 +17,7 @@ import { NPCSkillData } from "./data"; import { NPCActionSheetData, NPCSheetData, - NPCSheetItemData, + NPCSkillSheetData, NPCSpellcastingSheetData, NPCStrikeSheetData, NPCSystemSheetData, @@ -78,9 +77,7 @@ class NPCSheetPF2e extends CreatureSheetPF2e { this.#prepareSkills(sheetData.data); this.#prepareSaves(sheetData.data); await this.#prepareActions(sheetData); - sheetData.effectItems = sheetData.items.filter( - (data): data is NPCSheetItemData => data.type === "effect" - ); + sheetData.effectItems = this.actor.itemTypes.effect; sheetData.spellcastingEntries = await this.prepareSpellcasting(); } @@ -292,11 +289,11 @@ class NPCSheetPF2e extends CreatureSheetPF2e { #prepareSkills(sheetSystemData: NPCSystemSheetData): void { // Prepare a list of skill IDs sorted by their localized name // This will help in displaying the skills in alphabetical order in the sheet - const sortedSkillsIds = Object.keys(sheetSystemData.skills); + const sortedSkillsIds = Object.keys(sheetSystemData.skills) as SkillAbbreviation[]; const skills = sheetSystemData.skills; - for (const skillId of sortedSkillsIds) { - const skill = skills[skillId]; + for (const shortForm of sortedSkillsIds) { + const skill = skills[shortForm as SkillAbbreviation]; skill.label = objectHasKey(CONFIG.PF2E.skillList, skill.expanded) ? game.i18n.localize(CONFIG.PF2E.skillList[skill.expanded]) : skill.label ?? skill.slug; @@ -304,7 +301,7 @@ class NPCSheetPF2e extends CreatureSheetPF2e { skill.adjustedLower = skill.value < Number(skill.base); } - sortedSkillsIds.sort((a: string, b: string) => { + sortedSkillsIds.sort((a: SkillAbbreviation, b: SkillAbbreviation) => { const skillA = skills[a]; const skillB = skills[b]; @@ -320,7 +317,7 @@ class NPCSheetPF2e extends CreatureSheetPF2e { sortedSkills[skillId] = skills[skillId]; } - sheetSystemData.sortedSkills = sortedSkills; + sheetSystemData.sortedSkills = sortedSkills as Record; } #prepareSaves(systemData: NPCSystemSheetData): void { @@ -381,7 +378,7 @@ class NPCSheetPF2e extends CreatureSheetPF2e { }; for (const item of this.actor.itemTypes.action) { - const itemData = item.toObject(false) as unknown as ActionItemPF2e; + const itemData = item.toObject(false); const chatData = await item.getChatData(); const traits = chatData.traits ?? []; @@ -399,7 +396,7 @@ class NPCSheetPF2e extends CreatureSheetPF2e { chatData, traits, hasAura, - } as unknown as NPCSheetItemData); + }); } } diff --git a/src/module/actor/npc/skills-editor.ts b/src/module/actor/npc/skills-editor.ts index a070307cb74..c69c5124dd6 100644 --- a/src/module/actor/npc/skills-editor.ts +++ b/src/module/actor/npc/skills-editor.ts @@ -7,11 +7,11 @@ import { ErrorPF2e, objectHasKey } from "@util"; /** Specialized form to setup skills for an NPC character. */ export class NPCSkillsEditor extends FormApplication { - get npc() { + get npc(): NPCPF2e { return this.object; } - static override get defaultOptions() { + static override get defaultOptions(): FormApplicationOptions { const options = super.defaultOptions; options.id = "npc-skills-selector"; @@ -32,7 +32,7 @@ export class NPCSkillsEditor extends FormApplication { const { skills } = this.npc.system; for (const [key, skill] of Object.entries(skills)) { - if (this.isLoreSkill(key)) { + if (this.#isLoreSkill(key)) { skill.isLore = true; trainedSkills[key] = skill; } else if (skill.visible) { @@ -48,30 +48,30 @@ export class NPCSkillsEditor extends FormApplication { override activateListeners($html: JQuery): void { super.activateListeners($html); - $html.find(".delete").on("click", (event) => this.onClickRemoveSkill(event)); - $html.find(".add-lore-button").on("click", (event) => this.onClickAddLoreSkill(event)); - $html.find(".item-edit").on("click", (event) => this.onClickEditSkill(event)); - $html.find(".add-skill-button").on("click", (event) => this.onClickAddSkill(event)); + $html.find(".delete").on("click", (event) => this.#onClickRemoveSkill(event)); + $html.find(".add-lore-button").on("click", (event) => this.#onClickAddLoreSkill(event)); + $html.find(".item-edit").on("click", (event) => this.#onClickEditSkill(event)); + $html.find(".add-skill-button").on("click", (event) => this.#onClickAddSkill(event)); } - private async onClickAddSkill(eventData: JQuery.ClickEvent) { + async #onClickAddSkill(eventData: JQuery.ClickEvent) { eventData.preventDefault(); const skillSelector = $(eventData.currentTarget).parents("#skill-selector").find("select"); const skillId: string = skillSelector.val() as string; - const skillName = this.findSkillName(skillId); + const skillName = this.#findSkillName(skillId); const itemName = skillName.replace(/-/g, " ").titleCase(); await this.npc.createEmbeddedDocuments("Item", [{ name: itemName, type: "lore" }]); this.render(); } - private async onClickRemoveSkill(event: JQuery.ClickEvent) { + async #onClickRemoveSkill(event: JQuery.ClickEvent) { event.preventDefault(); const skillContainer = $(event.currentTarget).parents(".skill"); const skillId = skillContainer.attr("data-skill"); - const skillItem = this.findSkillItem(skillId ?? ""); + const skillItem = this.#findSkillItem(skillId ?? ""); if (skillItem) { skillContainer.remove(); @@ -83,7 +83,7 @@ export class NPCSkillsEditor extends FormApplication { } } - private async onClickAddLoreSkill(event: JQuery.ClickEvent): Promise { + async #onClickAddLoreSkill(event: JQuery.ClickEvent): Promise { event.preventDefault(); const loreNameField = $(event.currentTarget).parents("#lore-skill-creator").find("input"); @@ -99,9 +99,9 @@ export class NPCSkillsEditor extends FormApplication { this.render(); } - private onClickEditSkill(event: JQuery.ClickEvent): void { + #onClickEditSkill(event: JQuery.ClickEvent): void { const skillId = $(event.currentTarget).parents(".skill").attr("data-skill"); - const item = this.findSkillItem(skillId ?? ""); + const item = this.#findSkillItem(skillId ?? ""); if (!item) throw ErrorPF2e(`Unable to find item for skill ${skillId}.`); item.sheet.render(true); @@ -115,22 +115,22 @@ export class NPCSkillsEditor extends FormApplication { override async _updateObject(_event: Event, formData: Record): Promise { const updates = Object.entries(formData).flatMap(([key, modifier]) => { const value = Number(modifier) || 0; - const skillItem = this.findSkillItem(key); + const skillItem = this.#findSkillItem(key); if (!skillItem) return []; return { _id: skillItem.id, "system.mod.value": value }; }); await this.npc.updateEmbeddedDocuments("Item", updates); } - private isLoreSkill(skillId: string): boolean { - return !this.isRegularSkill(skillId); + #isLoreSkill(skillId: string): boolean { + return !this.#isRegularSkill(skillId); } /** * Checks if a skill is a regular skill or not. * @param skillId ID of the skill to check. */ - private isRegularSkill(skillId: string): boolean { + #isRegularSkill(skillId: string): boolean { for (const longForm of SKILL_LONG_FORMS) { if (longForm === skillId) return true; if (SKILL_EXPANDED[longForm].shortform === skillId) return true; @@ -143,7 +143,7 @@ export class NPCSkillsEditor extends FormApplication { * Converts from the 3-letter ID to the full, lower-letter name. * @param skillId ID of the skill. */ - private findSkillName(skillId: string): string { + #findSkillName(skillId: string): string { for (const longForm of SKILL_LONG_FORMS) { const skillData = SKILL_EXPANDED[longForm]; @@ -162,7 +162,7 @@ export class NPCSkillsEditor extends FormApplication { * defining the skill. They are of 'lore' type, even for non-lore skills. * @param skillId ID of the skill to search for. */ - private findSkillItem(skillId: string): Embedded | null { + #findSkillItem(skillId: string): LorePF2e | null { const { skills } = this.npc.system; const skillData = objectHasKey(skills, skillId) ? skills[skillId] : null; diff --git a/src/module/actor/npc/types.ts b/src/module/actor/npc/types.ts index 92a0f84ff72..644583a6dac 100644 --- a/src/module/actor/npc/types.ts +++ b/src/module/actor/npc/types.ts @@ -1,6 +1,6 @@ import { CreatureSheetData } from "@actor/creature/types"; import { HitPointsData, PerceptionData } from "@actor/data/base"; -import { SaveType } from "@actor/types"; +import { SaveType, SkillAbbreviation } from "@actor/types"; import { ActionItemPF2e, EffectPF2e, ItemPF2e } from "@item"; import { SpellcastingSheetData } from "@item/spellcasting-entry"; import { ZeroToFour } from "@module/data"; @@ -11,7 +11,7 @@ import { NPCArmorClass, NPCAttributes, NPCSaveData, NPCSkillData, NPCSystemData, interface ActionsDetails { label: string; - actions: NPCSheetItemData[]; + actions: NPCSheetItemData>[]; } interface NPCActionSheetData { @@ -39,6 +39,7 @@ interface VariantCloneParams { } type WithRank = { icon?: string; hover?: string; rank: ZeroToFour }; +type NPCSkillSheetData = NPCSkillData & WithAdjustments & WithRank; interface NPCSystemSheetData extends NPCSystemData { actions: NPCStrikeSheetData[]; @@ -53,9 +54,9 @@ interface NPCSystemSheetData extends NPCSystemData { localizedName?: string; }; }; - sortedSkills: Record; + sortedSkills: Record; saves: Record; - skills: Record; + skills: Record; traits: NPCTraitsData & { size: { localizedName?: string; @@ -74,10 +75,10 @@ interface NPCSpellcastingSheetData extends SpellcastingSheetData { } /** Additional fields added in sheet data preparation */ -interface NPCSheetData extends CreatureSheetData { +interface NPCSheetData extends CreatureSheetData { actions: NPCActionSheetData; data: NPCSystemSheetData; - items: NPCSheetItemData[]; + items: NPCSheetItemData>[]; effectItems: EffectPF2e[]; spellcastingEntries: SpellcastingSheetData[]; orphanedSpells: boolean; @@ -107,7 +108,7 @@ interface NPCSheetData extends CreatureSheetData languageDetails?: string; } -type NPCSheetItemData = T & { +type NPCSheetItemData> = RawObject & { glyph: string; imageUrl: string; traits: { @@ -135,6 +136,7 @@ export { NPCActionSheetData, NPCSheetData, NPCSheetItemData, + NPCSkillSheetData, NPCSpellcastingSheetData, NPCStrikeSheetData, NPCSystemSheetData, diff --git a/src/module/actor/party/document.ts b/src/module/actor/party/document.ts index 524a631f691..29a5a8ebf71 100644 --- a/src/module/actor/party/document.ts +++ b/src/module/actor/party/document.ts @@ -1,7 +1,8 @@ import { ActorPF2e, CharacterPF2e } from "@actor"; +import { TokenDocumentPF2e } from "@scene"; import { PartySource, PartySystemData } from "./data"; -class PartyPF2e extends ActorPF2e { +class PartyPF2e extends ActorPF2e { /** Friendship lives in our hearts */ override get canAct(): false { return false; @@ -19,7 +20,7 @@ class PartyPF2e extends ActorPF2e { } } -interface PartyPF2e extends ActorPF2e { +interface PartyPF2e extends ActorPF2e { readonly _source: PartySource; system: PartySystemData; } diff --git a/src/module/actor/sheet/base.ts b/src/module/actor/sheet/base.ts index 3ecefcd86e3..3541559c816 100644 --- a/src/module/actor/sheet/base.ts +++ b/src/module/actor/sheet/base.ts @@ -44,7 +44,7 @@ import { IWREditor } from "./popups/iwr-editor"; import { RemoveCoinsPopup } from "./popups/remove-coins-popup"; import { CraftingFormula } from "@actor/character/crafting"; import { UUIDUtils } from "@util/uuid-utils"; -import { CombatantPF2e } from "@module/encounter"; +import { CombatantPF2e, EncounterPF2e } from "@module/encounter"; /** * Extend the basic ActorSheet class to do all the PF2e things! @@ -140,7 +140,7 @@ abstract class ActorSheetPF2e extends ActorSheet { + const createInventoryItem = (item: PhysicalItemPF2e): InventoryItem => { const editable = game.user.isGM || item.isIdentified; const heldItems = item.isOfType("backpack") ? item.contents.map((i) => createInventoryItem(i)) : undefined; heldItems?.sort((a, b) => (a.item.sort || 0) - (b.item.sort || 0)); @@ -270,8 +270,8 @@ abstract class ActorSheetPF2e extends ActorSheet | null => { - const existing = game.combat.combatants.find((combatant) => combatant.actor === actor); + const combatant = ((): CombatantPF2e | null => { + const existing = game.combat.combatants.find((c) => c.actor === actor); if (existing) return existing; ui.notifications.error(game.i18n.format("PF2E.Encounter.NotParticipating", { actor: actor.name })); return null; @@ -803,7 +803,11 @@ abstract class ActorSheetPF2e extends ActorSheet { + protected override async _onSortItem( + event: ElementDragEvent, + itemSource: ItemSourcePF2e + ): Promise[]>; + protected override async _onSortItem(event: ElementDragEvent, itemSource: ItemSourcePF2e): Promise[]> { const item = this.actor.items.get(itemSource._id); if (!item) return []; @@ -844,14 +848,18 @@ abstract class ActorSheetPF2e extends ActorSheet { + async emulateItemDrop(data: DropCanvasItemDataPF2e): Promise[]> { return this._onDropItem({ preventDefault(): void {} } as ElementDragEvent, data); } - protected override async _onDropItem(event: ElementDragEvent, data: DropCanvasItemDataPF2e): Promise { + protected override async _onDropItem( + event: ElementDragEvent, + data: DropCanvasItemDataPF2e + ): Promise[]> { event.preventDefault(); + super._onDropItem; - const item = await ItemPF2e.fromDropData(data); + const item = (await ItemPF2e.fromDropData(data)) as ItemPF2e; if (!item) return []; const itemSource = item.toObject(); @@ -881,9 +889,14 @@ abstract class ActorSheetPF2e extends ActorSheet, data: DropCanvasItemDataPF2e - ): Promise { + ): Promise[]>; + protected async _handleDroppedItem( + event: ElementDragEvent, + item: ItemPF2e, + data: DropCanvasItemDataPF2e + ): Promise[]> { const { actor } = this; const itemSource = item.toObject(); @@ -993,9 +1006,13 @@ abstract class ActorSheetPF2e extends ActorSheet - ): Promise { + ): Promise[]>; + protected override async _onDropFolder( + _event: ElementDragEvent, + data: DropCanvasData<"Folder", Folder> + ): Promise[]> { if (!(this.actor.isOwner && data.documentName === "Item")) return []; - const folder = (await Folder.fromDropData(data)) as Folder | undefined; + const folder = (await Folder.fromDropData(data)) as Folder> | undefined; if (!folder) return []; const itemSources = [folder, ...folder.getSubfolders()].flatMap((f) => f.contents).map((i) => i.toObject()); return this._onDropItemCreate(itemSources); diff --git a/src/module/actor/sheet/data-types.ts b/src/module/actor/sheet/data-types.ts index 06cd73a0b65..bf863e967cf 100644 --- a/src/module/actor/sheet/data-types.ts +++ b/src/module/actor/sheet/data-types.ts @@ -1,7 +1,6 @@ import { ActorPF2e } from "@actor/base"; import { ActorSizePF2e } from "@actor/data/size"; import { InventoryBulk } from "@actor/inventory"; -import { LootPF2e } from "@actor/loot"; import { PhysicalItemPF2e } from "@item"; import { Coins } from "@item/physical/data"; import { PhysicalItemType } from "@item/physical/types"; @@ -54,7 +53,3 @@ export interface ActorSheetDataPF2e extends ActorSheet inventory: SheetInventory; enrichedContent: Record; } - -export interface LootSheetDataPF2e extends ActorSheetDataPF2e { - isLoot: boolean; -} diff --git a/src/module/actor/sheet/item-summary-renderer.ts b/src/module/actor/sheet/item-summary-renderer.ts index 0e3f3d6c70a..c15a7b1bfa9 100644 --- a/src/module/actor/sheet/item-summary-renderer.ts +++ b/src/module/actor/sheet/item-summary-renderer.ts @@ -34,7 +34,9 @@ export class ItemSummaryRenderer { if (itemType === "spellSlot") return; - const item = isFormula ? ((await fromUuid(itemId ?? "")) as Embedded) : actor.items.get(itemId ?? ""); + const item = isFormula + ? ((await fromUuid(itemId ?? "")) as ItemPF2e) + : actor.items.get(itemId ?? ""); const summary = await (async () => { const existing = htmlQuery(element, ":scope > .item-summary"); @@ -95,7 +97,7 @@ export class ItemSummaryRenderer { /** * Called when an item summary is expanded and needs to be filled out. */ - async renderItemSummary(div: HTMLElement, item: Embedded, chatData: ItemSummaryData): Promise { + async renderItemSummary(div: HTMLElement, item: ItemPF2e, chatData: ItemSummaryData): Promise { const description = isItemSystemData(chatData) ? chatData.description.value : await TextEditor.enrichHTML(item.description, { rollData: item.getRollData(), async: true }); diff --git a/src/module/actor/sheet/popups/ability-builder.ts b/src/module/actor/sheet/popups/ability-builder.ts index 481992d577f..966a63b7323 100644 --- a/src/module/actor/sheet/popups/ability-builder.ts +++ b/src/module/actor/sheet/popups/ability-builder.ts @@ -41,15 +41,15 @@ export class AbilityBuilderPopup extends Application { abilityScores: actor.abilities, manualKeyAbility: actor.keyAbility, keyOptions: build.keyOptions, - ancestryBoosts: this.calculateAncestryBoosts(), - backgroundBoosts: this.calculateBackgroundBoosts(), + ancestryBoosts: this.#calculateAncestryBoosts(), + backgroundBoosts: this.#calculateBackgroundBoosts(), alternateAncestryBoosts: !!actor.ancestry?.system.alternateAncestryBoosts, legacyFlaws: actor.ancestry?.system.voluntary?.boost !== undefined, - levelBoosts: this.calculatedLeveledBoosts(), + levelBoosts: this.#calculatedLeveledBoosts(), }; } - private calculateAncestryBoosts(): AncestryBoosts | null { + #calculateAncestryBoosts(): AncestryBoosts | null { const { actor } = this; const ancestry = actor.ancestry; if (!ancestry) return null; @@ -152,7 +152,7 @@ export class AbilityBuilderPopup extends Application { }; } - private calculateBackgroundBoosts(): BackgroundBoosts | null { + #calculateBackgroundBoosts(): BackgroundBoosts | null { const { actor } = this; if (!actor.background) return null; @@ -214,7 +214,7 @@ export class AbilityBuilderPopup extends Application { }; } - private calculatedLeveledBoosts() { + #calculatedLeveledBoosts() { const build = this.actor.system.build.abilities; const isGradual = game.settings.get("pf2e", "gradualBoostsVariant"); return ([1, 5, 10, 15, 20] as const).reduce( @@ -450,9 +450,9 @@ interface AbilityBuilderSheetData { abilityScores: Abilities; manualKeyAbility: AbilityString; abilities: Record; - ancestry: Embedded | null; - background: Embedded | null; - class: Embedded | null; + ancestry: AncestryPF2e | null; + background: BackgroundPF2e | null; + class: ClassPF2e | null; manual: boolean; ancestryBoosts: AncestryBoosts | null; backgroundBoosts: BackgroundBoosts | null; diff --git a/src/module/actor/sheet/spellcasting-dialog.ts b/src/module/actor/sheet/spellcasting-dialog.ts index dedde05711d..53269e19957 100644 --- a/src/module/actor/sheet/spellcasting-dialog.ts +++ b/src/module/actor/sheet/spellcasting-dialog.ts @@ -4,7 +4,7 @@ import { SpellcastingEntryPF2e } from "@item"; import { SpellcastingEntrySource, SpellcastingEntrySystemSource } from "@item/spellcasting-entry/data"; import { omit, pick } from "@util"; -function createEmptySpellcastingEntry(actor: ActorPF2e): Embedded { +function createEmptySpellcastingEntry(actor: ActorPF2e): SpellcastingEntryPF2e { return new SpellcastingEntryPF2e( { name: "Untitled", @@ -17,14 +17,14 @@ function createEmptySpellcastingEntry(actor: ActorPF2e): Embedded; + ) as SpellcastingEntryPF2e; } /** Dialog to create or edit spellcasting entries. It works on a clone of spellcasting entry, but will not persist unless the changes are accepted */ -class SpellcastingCreateAndEditDialog extends FormApplication> { +class SpellcastingCreateAndEditDialog extends FormApplication> { private actor: ActorPF2e; - constructor(object: ActorPF2e | Embedded, options: Partial) { + constructor(object: ActorPF2e | SpellcastingEntryPF2e, options: Partial) { super( object instanceof ActorPF2e ? createEmptySpellcastingEntry(object) : object.clone({}, { keepId: true }), options @@ -160,7 +160,7 @@ class SpellcastingCreateAndEditDialog extends FormApplication> { +interface SpellcastingCreateAndEditDialogSheetData extends FormApplicationData> { actor: ActorPF2e; data: SpellcastingEntrySystemSource; classDCs: ClassDCData[]; @@ -170,7 +170,10 @@ interface SpellcastingCreateAndEditDialogSheetData extends FormApplicationData) { +export async function createSpellcastingDialog( + event: MouseEvent, + object: ActorPF2e | SpellcastingEntryPF2e +) { const dialog = new SpellcastingCreateAndEditDialog(object, { top: event.clientY - 80, left: window.innerWidth - 710, diff --git a/src/module/actor/sheet/trick-magic-item-popup.ts b/src/module/actor/sheet/trick-magic-item-popup.ts index 7075a0b1ec4..42c095e2e1a 100644 --- a/src/module/actor/sheet/trick-magic-item-popup.ts +++ b/src/module/actor/sheet/trick-magic-item-popup.ts @@ -1,4 +1,4 @@ -import { CharacterPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e } from "@actor"; import { ConsumablePF2e } from "@item"; import { calculateTrickMagicItemCheckDC, TrickMagicItemDifficultyData } from "@item/consumable/spell-consumables"; import { TrickMagicItemEntry, TrickMagicItemSkill, TRICK_MAGIC_SKILLS } from "@item/spellcasting-entry/trick"; @@ -7,7 +7,7 @@ import { ErrorPF2e } from "@util"; export class TrickMagicItemPopup { /** The wand or scroll being "tricked" */ - readonly item: Embedded; + readonly item: ConsumablePF2e; /** The actor doing the tricking */ readonly actor!: CharacterPF2e; @@ -15,9 +15,9 @@ export class TrickMagicItemPopup { /** The skill DC of the action's check */ readonly checkDC: TrickMagicItemDifficultyData; - private translations = LocalizePF2e.translations.PF2E.TrickMagicItemPopup; + #translations = LocalizePF2e.translations.PF2E.TrickMagicItemPopup; - constructor(item: Embedded) { + constructor(item: ConsumablePF2e) { if (!item.isOfType("consumable")) { throw ErrorPF2e("Unexpected item used for Trick Magic Item"); } @@ -26,15 +26,15 @@ export class TrickMagicItemPopup { this.checkDC = calculateTrickMagicItemCheckDC(item); if (!(item.actor instanceof CharacterPF2e)) { - ui.notifications.warn(this.translations.InvalidActor); + ui.notifications.warn(this.#translations.InvalidActor); return; } this.actor = item.actor; - this.initialize(); + this.#initialize(); } - private async initialize() { + async #initialize(): Promise { const skills = TRICK_MAGIC_SKILLS.filter((skill) => skill in this.checkDC).map((value) => ({ value, label: game.i18n.localize(`PF2E.Skill${value.capitalize()}`), @@ -44,21 +44,21 @@ export class TrickMagicItemPopup { const button: DialogButton = { icon: '', label: `${skill.label} (${skill.modifier < 0 ? "" : "+"}${skill.modifier})`, - callback: () => this.handleTrickItem(skill.value), + callback: () => this.#handleTrickItem(skill.value), }; return { ...accumulated, [skill.value]: button }; }, {}); new Dialog( { - title: this.translations.Title, - content: `

${this.translations.Label}

`, + title: this.#translations.Title, + content: `

${this.#translations.Label}

`, buttons, }, { classes: ["dialog", "trick-magic-item"], width: "auto" } ).render(true); } - handleTrickItem(skill: TrickMagicItemSkill) { + #handleTrickItem(skill: TrickMagicItemSkill): void { const stat = this.actor.skills[skill]; stat.check.roll({ extraRollOptions: ["action:trick-magic-item"], diff --git a/src/module/actor/spellcasting.ts b/src/module/actor/spellcasting.ts index 98725a5464f..210c6cc3599 100644 --- a/src/module/actor/spellcasting.ts +++ b/src/module/actor/spellcasting.ts @@ -6,11 +6,11 @@ import { RitualSpellcasting } from "@item/spellcasting-entry/rituals"; import { BaseSpellcastingEntry } from "@item/spellcasting-entry/types"; import { ErrorPF2e } from "@util"; -export class ActorSpellcasting extends Collection { +export class ActorSpellcasting extends Collection> { /** All available spell lists on this actor */ - collections = new Collection(); + collections = new Collection>>(); - constructor(public readonly actor: ActorPF2e, entries: BaseSpellcastingEntry[]) { + constructor(public readonly actor: TActor, entries: BaseSpellcastingEntry[]) { super(entries.map((entry) => [entry.id, entry])); for (const entry of entries) { @@ -19,12 +19,12 @@ export class ActorSpellcasting extends Collection { } /** Returns a list of entries pre-filtered to SpellcastingEntryPF2e */ - get regular(): SpellcastingEntryPF2e[] { - return this.filter((e): e is SpellcastingEntryPF2e => e instanceof SpellcastingEntryPF2e); + get regular(): SpellcastingEntryPF2e[] { + return this.filter((e): e is SpellcastingEntryPF2e => e instanceof SpellcastingEntryPF2e); } /** Get this actor's ritual casting ability */ - get ritual(): RitualSpellcasting | null { + get ritual(): RitualSpellcasting | null { const ritualCasting = this.collections.get("rituals")?.entry; return ritualCasting instanceof RitualSpellcasting ? ritualCasting : null; } @@ -33,7 +33,7 @@ export class ActorSpellcasting extends Collection { * All spellcasting entries that count as prepared/spontaneous, which qualify as a * full fledged spellcasting feature for wands and scrolls. */ - get spellcastingFeatures(): SpellcastingEntryPF2e[] { + get spellcastingFeatures(): SpellcastingEntryPF2e[] { return this.regular.filter((e) => e.isPrepared || e.isSpontaneous); } diff --git a/src/module/actor/types.ts b/src/module/actor/types.ts index 7cdb773a9d3..0f89e45e7b3 100644 --- a/src/module/actor/types.ts +++ b/src/module/actor/types.ts @@ -1,11 +1,14 @@ +import * as ActorInstance from "@actor"; import { ActorPF2e } from "@actor"; -import { MeleePF2e, SpellPF2e, WeaponPF2e } from "@item"; +import * as ItemInstance from "@item"; import { EffectTrait } from "@item/abstract-effect"; +import { ItemInstances } from "@item/types"; import { TokenDocumentPF2e } from "@scene"; import { immunityTypes, resistanceTypes, weaknessTypes } from "@scripts/config/iwr"; import { DamageRoll } from "@system/damage/roll"; import { CheckDC } from "@system/degree-of-success"; import { PredicatePF2e } from "@system/predication"; +import { StatisticCheck } from "@system/statistic"; import { TraitViewData } from "./data/base"; import { ModifierPF2e, StatisticModifier } from "./modifiers"; import { @@ -16,8 +19,22 @@ import { SKILL_LONG_FORMS, UNAFFECTED_TYPES, } from "./values"; -import { StatisticCheck } from "@system/statistic"; +/** Used exclusively to resolve `ActorPF2e#isOfType` */ +interface ActorInstances { + character: ActorInstance.CharacterPF2e; + creature: ActorInstance.CreaturePF2e; + familiar: ActorInstance.FamiliarPF2e; + hazard: ActorInstance.HazardPF2e; + loot: ActorInstance.LootPF2e; + party: ActorInstance.PartyPF2e; + npc: ActorInstance.NPCPF2e; + vehicle: ActorInstance.VehiclePF2e; +} + +type EmbeddedItemInstances = { + [K in keyof ItemInstances]: ItemInstances[K][]; +}; type AbilityString = SetElement; interface ActorDimensions { @@ -67,7 +84,10 @@ interface AuraColors { /* Attack Rolls */ /* -------------------------------------------- */ -type AttackItem = WeaponPF2e | MeleePF2e | SpellPF2e; +type AttackItem = + | ItemInstance.WeaponPF2e + | ItemInstance.MeleePF2e + | ItemInstance.SpellPF2e; interface StrikeSelf< TActor extends ActorPF2e = ActorPF2e, @@ -153,6 +173,7 @@ export { AbilityString, ActorAlliance, ActorDimensions, + ActorInstances, ApplyDamageParams, AttackItem, AttackRollContext, @@ -162,6 +183,7 @@ export { AuraData, AuraEffectData, DCSlug, + EmbeddedItemInstances, IWRType, ImmunityType, ResistanceType, diff --git a/src/module/actor/vehicle/document.ts b/src/module/actor/vehicle/document.ts index 08bdc9a23a4..a8ead9623eb 100644 --- a/src/module/actor/vehicle/document.ts +++ b/src/module/actor/vehicle/document.ts @@ -8,7 +8,7 @@ import { Statistic } from "@system/statistic"; import { ActorPF2e, HitPointsSummary } from "../base"; import { TokenDimensions, VehicleSource, VehicleSystemData } from "./data"; -class VehiclePF2e extends ActorPF2e { +class VehiclePF2e extends ActorPF2e { override get allowedItemTypes(): (ItemType | "physical")[] { return [...super.allowedItemTypes, "physical", "action"]; } @@ -167,7 +167,7 @@ class VehiclePF2e extends ActorPF2e { protected override async _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { await super._preUpdate(changed, options, user); @@ -190,7 +190,7 @@ class VehiclePF2e extends ActorPF2e { } } -interface VehiclePF2e extends ActorPF2e { +interface VehiclePF2e extends ActorPF2e { readonly _source: VehicleSource; system: VehicleSystemData; diff --git a/src/module/actor/vehicle/sheet.ts b/src/module/actor/vehicle/sheet.ts index 2bbde056640..a9129fb0948 100644 --- a/src/module/actor/vehicle/sheet.ts +++ b/src/module/actor/vehicle/sheet.ts @@ -40,18 +40,19 @@ export class VehicleSheetPF2e extends ActorSheetPF2e { const actorData = sheetData.actor; // Actions - const actions: Record<"action" | "reaction" | "free", { label: string; actions: ActionItemPF2e[] }> = { - action: { label: game.i18n.localize("PF2E.ActionsActionsHeader"), actions: [] }, - reaction: { label: game.i18n.localize("PF2E.ActionsReactionsHeader"), actions: [] }, - free: { label: game.i18n.localize("PF2E.ActionsFreeActionsHeader"), actions: [] }, - }; + const actions: Record<"action" | "reaction" | "free", { label: string; actions: RawObject[] }> = + { + action: { label: game.i18n.localize("PF2E.ActionsActionsHeader"), actions: [] }, + reaction: { label: game.i18n.localize("PF2E.ActionsReactionsHeader"), actions: [] }, + free: { label: game.i18n.localize("PF2E.ActionsFreeActionsHeader"), actions: [] }, + }; // Actions for (const item of this.actor.itemTypes.action.sort((a, b) => a.sort - b.sort)) { - const itemData = item.toObject(false) as unknown as ActionItemPF2e; + const itemData = item.toObject(false); const img = getActionIcon(item.actionCost); const actionType = item.actionCost?.type ?? "free"; - actions[actionType].actions.push({ ...itemData, img } as ActionItemPF2e); + actions[actionType].actions.push({ ...itemData, img }); } actorData.actions = actions; diff --git a/src/module/apps/hotbar.ts b/src/module/apps/hotbar.ts index 642125d92b0..3d0e9b4de5a 100644 --- a/src/module/apps/hotbar.ts +++ b/src/module/apps/hotbar.ts @@ -87,7 +87,7 @@ if (!actor) { }`; const toggleMacro = - game.macros.find((m) => m.name === name && m.data.command === command) ?? + game.macros.find((m) => m.name === name && m.command === command) ?? (await MacroPF2e.create({ type: "script", name, img, command }, { renderSheet: false })) ?? null; diff --git a/src/module/apps/pick-a-thing-prompt.ts b/src/module/apps/pick-a-thing-prompt.ts index 19178bb1b9a..31ae2a15601 100644 --- a/src/module/apps/pick-a-thing-prompt.ts +++ b/src/module/apps/pick-a-thing-prompt.ts @@ -6,7 +6,7 @@ import Tagify from "@yaireo/tagify"; /** Prompt the user to pick from a number of options */ abstract class PickAThingPrompt extends Application { - protected item: Embedded; + protected item: ItemPF2e; private resolve?: (value: PickableThing | null) => void; @@ -141,7 +141,7 @@ interface PickAThingConstructorArgs { title?: string; prompt?: string; choices?: PickableThing[]; - item: Embedded; + item: ItemPF2e; predicate?: PredicatePF2e; allowNoSelection?: boolean; } diff --git a/src/module/apps/sidebar/actor-directory.ts b/src/module/apps/sidebar/actor-directory.ts index dff0e808757..aa943f59475 100644 --- a/src/module/apps/sidebar/actor-directory.ts +++ b/src/module/apps/sidebar/actor-directory.ts @@ -2,7 +2,7 @@ import { ActorPF2e } from "@actor/base"; import { fontAwesomeIcon, htmlQuery, htmlQueryAll } from "@util"; /** Extend ActorDirectory to show more information */ -export class ActorDirectoryPF2e extends ActorDirectory { +export class ActorDirectoryPF2e> extends ActorDirectory { static override get defaultOptions(): SidebarDirectoryOptions { const options = super.defaultOptions; options.renderUpdateKeys.push("system.details.level.value", "system.attributes.adjustment"); diff --git a/src/module/apps/sidebar/chat-log.ts b/src/module/apps/sidebar/chat-log.ts index b117c738e7a..aec6ccf91da 100644 --- a/src/module/apps/sidebar/chat-log.ts +++ b/src/module/apps/sidebar/chat-log.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ArmorPF2e } from "@item"; import { TokenPF2e } from "@module/canvas"; import { ChatMessagePF2e } from "@module/chat-message"; @@ -11,7 +12,7 @@ export class ChatLogPF2e extends ChatLog { protected override async _processDiceCommand( command: string, matches: RegExpMatchArray[], - chatData: DeepPartial, + chatData: DeepPartial, createOptions: ChatMessageModificationContext ): Promise { const actor = ChatMessage.getSpeakerActor(chatData.speaker ?? {}) || game.user.character; @@ -104,7 +105,7 @@ export class ChatLogPF2e extends ChatLog { } return tokens; }; - const getNonBrokenShields = (tokens: TokenPF2e[]): Embedded[] => { + const getNonBrokenShields = (tokens: TokenPF2e[]): ArmorPF2e[] => { const actor = tokens[0].actor!; const heldShields = actor.itemTypes.armor.filter((armor) => armor.isEquipped && armor.isShield); return heldShields.filter((shield) => !shield.isBroken); diff --git a/src/module/apps/sidebar/compendium-directory.ts b/src/module/apps/sidebar/compendium-directory.ts index 2b559e2bb4f..ef85e6d569c 100644 --- a/src/module/apps/sidebar/compendium-directory.ts +++ b/src/module/apps/sidebar/compendium-directory.ts @@ -83,7 +83,7 @@ export class CompendiumDirectoryPF2e extends CompendiumDirectory { }, callback: async ($li) => { const compendium = game.packs.get($li.data("pack"), { strict: true }) as CompendiumCollection< - ActorPF2e | ItemPF2e + ActorPF2e | ItemPF2e >; const runner = new MigrationRunner(MigrationList.constructFromVersion(null)); runner.runCompendiumMigration(compendium); @@ -116,7 +116,9 @@ export class CompendiumDirectoryPF2e extends CompendiumDirectory { const packCollection = game.packs.get(UUIDUtils.fromUuidSync(uuid)?.pack ?? "", { strict: true }); const worldCollection = game.collections.get(packCollection.documentName, { strict: true }); const indexData = UUIDUtils.fromUuidSync(uuid) ?? { _id: "" }; - if (!("_id" in indexData)) throw ErrorPF2e("Unexpected missing document _id"); + if (!("_id" in indexData && typeof indexData._id === "string")) { + throw ErrorPF2e("Unexpected missing document _id"); + } return worldCollection.importFromCompendium( packCollection, diff --git a/src/module/apps/sidebar/item-directory.ts b/src/module/apps/sidebar/item-directory.ts index 204d7afb205..1d057e4d3aa 100644 --- a/src/module/apps/sidebar/item-directory.ts +++ b/src/module/apps/sidebar/item-directory.ts @@ -1,7 +1,8 @@ +import { ItemPF2e } from "@item"; import { fontAwesomeIcon, htmlQuery, htmlQueryAll } from "@util"; /** Extend ItemDirectory to show more information */ -export class ItemDirectoryPF2e extends ItemDirectory { +export class ItemDirectoryPF2e> extends ItemDirectory { static override get defaultOptions(): SidebarDirectoryOptions { const options = super.defaultOptions; options.renderUpdateKeys.push("system.level.value"); diff --git a/src/module/canvas/ambient-light.ts b/src/module/canvas/ambient-light.ts index 17719206388..4c1a3d33e3d 100644 --- a/src/module/canvas/ambient-light.ts +++ b/src/module/canvas/ambient-light.ts @@ -1,13 +1,18 @@ import { AmbientLightDocumentPF2e } from "@module/scene"; import { LightingLayerPF2e } from "."; -export class AmbientLightPF2e extends AmbientLight { +class AmbientLightPF2e< + TParent extends AmbientLightDocumentPF2e = AmbientLightDocumentPF2e +> extends AmbientLight { /** Is this light actually a source of darkness? */ get isDarkness(): boolean { return this.source.isDarkness; } } -export interface AmbientLightPF2e { +interface AmbientLightPF2e + extends AmbientLight { get layer(): LightingLayerPF2e; } + +export { AmbientLightPF2e }; diff --git a/src/module/canvas/drop-canvas-data.ts b/src/module/canvas/drop-canvas-data.ts index a5d9b7aaf4a..3a52297f9be 100644 --- a/src/module/canvas/drop-canvas-data.ts +++ b/src/module/canvas/drop-canvas-data.ts @@ -7,6 +7,7 @@ export type DropCanvasItemDataPF2e = DropCanvasData<"Item", ItemPF2e> & { context?: EffectContextData; }; -export type DropCanvasDataPF2e = T extends "Item" - ? DropCanvasItemDataPF2e - : DropCanvasData; +export type DropCanvasDataPF2e< + TDocumentType extends string = string, + TObject extends object = object +> = TDocumentType extends "Item" ? DropCanvasItemDataPF2e : DropCanvasData; diff --git a/src/module/canvas/measured-template.ts b/src/module/canvas/measured-template.ts index 070c1cd5dd0..48eb02c6f1f 100644 --- a/src/module/canvas/measured-template.ts +++ b/src/module/canvas/measured-template.ts @@ -1,8 +1,11 @@ import { MeasuredTemplateDocumentPF2e } from "@module/scene/measured-template-document"; import { TemplateLayerPF2e } from "."; import { highlightGrid } from "./helpers"; +import { ScenePF2e } from "@scene"; -class MeasuredTemplatePF2e extends MeasuredTemplate { +class MeasuredTemplatePF2e< + TDocument extends MeasuredTemplateDocumentPF2e = MeasuredTemplateDocumentPF2e +> extends MeasuredTemplate { /** Track the timestamp when the last mouse move event was captured. */ #moveTime = 0; @@ -101,7 +104,9 @@ class MeasuredTemplatePF2e extends MeasuredTemplate { +interface MeasuredTemplatePF2e< + TDocument extends MeasuredTemplateDocumentPF2e = MeasuredTemplateDocumentPF2e +> extends MeasuredTemplate { get layer(): TemplateLayerPF2e; } diff --git a/src/module/canvas/status-effects.ts b/src/module/canvas/status-effects.ts index 1c966ea5a2a..c105aa84254 100644 --- a/src/module/canvas/status-effects.ts +++ b/src/module/canvas/status-effects.ts @@ -263,7 +263,9 @@ export class StatusEffects { } /** Creates a ChatMessage with the Actors current status effects. */ - static #createChatMessage(token: TokenPF2e, whisper = false) { + static #createChatMessage(token: TokenPF2e | null, whisper = false): Promise | null { + if (!token) return null; + // Get the active applied conditions. // Iterate the list to create the chat and bubble chat dialog. const conditions = token.actor?.itemTypes.condition.filter((c) => c.active) ?? []; @@ -279,7 +281,7 @@ export class StatusEffects { `; }); - if (statusEffectList.length === 0) return; + if (statusEffectList.length === 0) return null; const content = `
@@ -291,7 +293,7 @@ export class StatusEffects {
`; - const messageSource: DeepPartial = { + const messageSource: DeepPartial = { user: game.user.id, speaker: { alias: game.i18n.format("PF2E.StatusEffects", { name: token.name }) }, content, @@ -302,7 +304,8 @@ export class StatusEffects { if (hideNPCEvent || whisper) { messageSource.whisper = ChatMessage.getWhisperRecipients("GM").map((u) => u.id); } - ChatMessagePF2e.create(messageSource); + + return ChatMessagePF2e.create(messageSource); } /** Re-render the token HUD */ diff --git a/src/module/canvas/token/object.ts b/src/module/canvas/token/object.ts index 2000486b77b..208bf0dba15 100644 --- a/src/module/canvas/token/object.ts +++ b/src/module/canvas/token/object.ts @@ -2,18 +2,18 @@ import { ANIMAL_COMPANION_SOURCE_ID } from "@actor/values"; import { EffectPF2e } from "@item"; import { TokenDocumentPF2e } from "@module/scene"; import { pick } from "@util"; -import { CanvasPF2e, measureDistanceCuboid, TokenLayerPF2e } from ".."; +import { CanvasPF2e, TokenLayerPF2e, measureDistanceCuboid } from ".."; import { HearingSource } from "../perception/hearing-source"; import { AuraRenderers } from "./aura"; -class TokenPF2e extends Token { +class TokenPF2e extends Token { /** Visual representation and proximity-detection facilities for auras */ readonly auras: AuraRenderers; /** The token's line hearing source */ hearing: HearingSource; - constructor(document: TokenDocumentPF2e) { + constructor(document: TDocument) { super(document); this.hearing = new HearingSource(this); @@ -385,7 +385,7 @@ class TokenPF2e extends Token { } /** Destroy auras before removing this token from the canvas */ - override _onDelete(options: DocumentModificationContext, userId: string): void { + override _onDelete(options: DocumentModificationContext, userId: string): void { super._onDelete(options, userId); this.auras.clear(); } @@ -407,7 +407,7 @@ class TokenPF2e extends Token { } } -interface TokenPF2e extends Token { +interface TokenPF2e extends Token { get layer(): TokenLayerPF2e; icon?: TokenImage; diff --git a/src/module/chat-message/crit-fumble-cards.ts b/src/module/chat-message/crit-fumble-cards.ts index 1caf527986b..00bf5eed8df 100644 --- a/src/module/chat-message/crit-fumble-cards.ts +++ b/src/module/chat-message/crit-fumble-cards.ts @@ -38,7 +38,7 @@ export class CriticalHitAndFumbleCards { .getDocument(tableId) .then((rollTable) => { rollTable!.draw({ displayChat: false }).then((draw) => { - const data: { roll: Roll; messageData: Partial } = { + const data: { roll: Roll; messageData: Partial } = { roll: draw.roll, messageData: {}, }; diff --git a/src/module/chat-message/data.ts b/src/module/chat-message/data.ts index 5247e9daf7d..1ab3aa978d0 100644 --- a/src/module/chat-message/data.ts +++ b/src/module/chat-message/data.ts @@ -2,21 +2,16 @@ import { ItemType } from "@item/data"; import { MagicTradition } from "@item/spell/types"; import { BaseRawModifier } from "@actor/modifiers"; import { DegreeAdjustmentsRecord, DegreeOfSuccessString } from "@system/degree-of-success"; -import { ChatMessagePF2e } from "."; import { RollNoteSource } from "@module/notes"; import { CheckRollContext } from "@system/check"; import { DamageRollContext } from "@system/damage"; import { ZeroToTwo } from "@module/data"; -interface ChatMessageDataPF2e extends foundry.data.ChatMessageData { - readonly _source: ChatMessageSourcePF2e; -} - -interface ChatMessageSourcePF2e extends foundry.data.ChatMessageSource { +interface ChatMessageSourcePF2e extends foundry.documents.ChatMessageSource { flags: ChatMessageFlagsPF2e; } -type ChatMessageFlagsPF2e = foundry.data.ChatMessageFlags & { +type ChatMessageFlagsPF2e = foundry.documents.ChatMessageFlags & { pf2e: { damageRoll?: DamageRollFlag; context?: ChatContextFlag; @@ -31,7 +26,7 @@ type ChatMessageFlagsPF2e = foundry.data.ChatMessageFlags & { strike?: StrikeLookupData | null; [key: string]: unknown; }; - core: NonNullable; + core: NonNullable; }; type ChatContextFlag = CheckRollContextFlag | DamageRollContextFlag | SpellCastContextFlag; @@ -107,7 +102,6 @@ interface SpellCastContextFlag { export { ChatContextFlag, - ChatMessageDataPF2e, ChatMessageSourcePF2e, ChatMessageFlagsPF2e, CheckRollContextFlag, diff --git a/src/module/chat-message/document.ts b/src/module/chat-message/document.ts index 3facdca6ff4..da255ef8431 100644 --- a/src/module/chat-message/document.ts +++ b/src/module/chat-message/document.ts @@ -3,7 +3,7 @@ import { StrikeData } from "@actor/data/base"; import { ItemPF2e, ItemProxyPF2e } from "@item"; import { traditionSkills, TrickMagicItemEntry } from "@item/spellcasting-entry/trick"; import { UserPF2e } from "@module/user"; -import { TokenDocumentPF2e } from "@scene"; +import { ScenePF2e, TokenDocumentPF2e } from "@scene"; import { InlineRollLinks } from "@scripts/ui/inline-roll-links"; import { UserVisibilityPF2e } from "@scripts/ui/user-visibility"; import { CheckRoll } from "@system/check"; @@ -11,10 +11,10 @@ import { DamageRoll } from "@system/damage/roll"; import { htmlQuery, htmlQueryAll, parseHTML } from "@util"; import { ChatRollDetails } from "./chat-roll-details"; import { CriticalHitAndFumbleCards } from "./crit-fumble-cards"; -import { ChatMessageDataPF2e, ChatMessageFlagsPF2e, ChatMessageSourcePF2e, StrikeLookupData } from "./data"; +import { ChatMessageFlagsPF2e, ChatMessageSourcePF2e, StrikeLookupData } from "./data"; import * as Listeners from "./listeners"; -class ChatMessagePF2e extends ChatMessage { +class ChatMessagePF2e extends ChatMessage { /** The chat log doesn't wait for data preparation before rendering, so set some data in the constructor */ constructor(data: DeepPartial = {}, context: DocumentConstructionContext = {}) { data.flags = mergeObject(expandObject(data.flags ?? {}), { core: {}, pf2e: {} }); @@ -50,7 +50,7 @@ class ChatMessagePF2e extends ChatMessage { } /** If this is a check or damage roll, it will have target information */ - get target(): { actor: ActorPF2e; token: Embedded } | null { + get target(): { actor: ActorPF2e; token: TokenDocumentPF2e } | null { const context = this.flags.pf2e.context; if (!context) return null; const targetUUID = "target" in context ? context.target?.token : null; @@ -96,10 +96,10 @@ class ChatMessagePF2e extends ChatMessage { } /** Get the owned item associated with this chat message */ - get item(): Embedded | null { + get item(): ItemPF2e | null { // If this is a strike, we usually want the strike's item const strike = this._strike; - if (strike?.item) return strike.item as Embedded; + if (strike?.item) return strike.item; const item = (() => { const domItem = this.getItemFromDOM(); @@ -155,7 +155,7 @@ class ChatMessagePF2e extends ChatMessage { } /** Get stringified item source from the DOM-rendering of this chat message */ - getItemFromDOM(): Embedded | null { + getItemFromDOM(): ItemPF2e | null { const $domMessage = $("ol#chat-log").children(`li[data-message-id="${this.id}"]`); const sourceString = $domMessage.find("div.pf2e.item-card").attr("data-embedded-item") ?? "null"; try { @@ -166,7 +166,7 @@ class ChatMessagePF2e extends ChatMessage { fromConsumable: this.flags?.pf2e?.isFromConsumable, }) : null; - return item as Embedded | null; + return item as ItemPF2e | null; } catch (_error) { return null; } @@ -178,7 +178,7 @@ class ChatMessagePF2e extends ChatMessage { } /** Get the token of the speaker if possible */ - get token(): Embedded | null { + get token(): TokenDocumentPF2e | null { if (!game.scenes) return null; const sceneId = this.speaker.scene ?? ""; const tokenId = this.speaker.token ?? ""; @@ -286,11 +286,7 @@ class ChatMessagePF2e extends ChatMessage { } } - protected override _onCreate( - data: foundry.data.ChatMessageSource, - options: DocumentModificationContext, - userId: string - ) { + protected override _onCreate(data: this["_source"], options: DocumentModificationContext, userId: string) { super._onCreate(data, options, userId); // Handle critical hit and fumble card drawing @@ -300,15 +296,15 @@ class ChatMessagePF2e extends ChatMessage { } } -interface ChatMessagePF2e extends ChatMessage { - readonly data: ChatMessageDataPF2e; +interface ChatMessagePF2e extends ChatMessage { + readonly _source: ChatMessageSourcePF2e; flags: ChatMessageFlagsPF2e; get user(): UserPF2e; } declare namespace ChatMessagePF2e { - function getSpeakerActor(speaker: foundry.data.ChatSpeakerSource | foundry.data.ChatSpeakerData): ActorPF2e | null; + function getSpeakerActor(speaker: foundry.documents.ChatSpeakerData): ActorPF2e | null; } export { ChatMessagePF2e }; diff --git a/src/module/chat-message/listeners/cards.ts b/src/module/chat-message/listeners/cards.ts index b6316a50094..e0165293405 100644 --- a/src/module/chat-message/listeners/cards.ts +++ b/src/module/chat-message/listeners/cards.ts @@ -220,7 +220,7 @@ export const ChatCards = { }: { event: JQuery.ClickEvent; actor: ActorPF2e; - item: Embedded; + item: ItemPF2e; }): Promise => { if (canvas.tokens.controlled.length > 0) { const saveType = event.currentTarget.dataset.save; diff --git a/src/module/chat-message/listeners/set-as-initiative.ts b/src/module/chat-message/listeners/set-as-initiative.ts index 6571217ca5c..4ee99262af9 100644 --- a/src/module/chat-message/listeners/set-as-initiative.ts +++ b/src/module/chat-message/listeners/set-as-initiative.ts @@ -1,6 +1,6 @@ import { SkillLongForm } from "@actor/types"; import { SKILL_LONG_FORMS } from "@actor/values"; -import { CombatantPF2e } from "@module/encounter"; +import { CombatantPF2e, EncounterPF2e } from "@module/encounter"; import { fontAwesomeIcon, setHasElement } from "@util"; /** Add a button to set a check roll as the roller's initiative */ @@ -44,8 +44,8 @@ export const SetAsInitiative = { const actor = message.token?.actor; if (!actor) return; - const combatant = ((): Embedded | null => { - const existing = game.combat.combatants.find((combatant) => combatant.actor === actor); + const combatant = ((): CombatantPF2e | null => { + const existing = game.combat.combatants.find((c) => c.actor === actor); if (existing) return existing; ui.notifications.error(game.i18n.format("PF2E.Encounter.NotParticipating", { actor: actor.name })); return null; diff --git a/src/module/collection/actors.ts b/src/module/collection/actors.ts index 42ee6956473..528705f930c 100644 --- a/src/module/collection/actors.ts +++ b/src/module/collection/actors.ts @@ -1,7 +1,7 @@ import { ActorPF2e } from "@actor"; import { ActorUpdateContext } from "@actor/base"; -export class ActorsPF2e extends Actors { +export class ActorsPF2e> extends Actors { /** Work around a bug as of Foundry V9.242 in which token default settings are ignored for compendium imports */ override fromCompendium(actor: TActor | TActor["_source"], options?: FromCompendiumOptions) { const defaultToken = deepClone(game.settings.get("core", "defaultToken")); @@ -19,7 +19,7 @@ export class ActorsPF2e extends Actors, actorId: string, updateData?: DocumentUpdateData, - options?: ActorUpdateContext + options?: ActorUpdateContext ): Promise { const actor = await super.importFromCompendium(pack, actorId, updateData, options); if (!actor) return actor; diff --git a/src/module/data.ts b/src/module/data.ts index 8a7d4c53b3e..34a3bb9830f 100644 --- a/src/module/data.ts +++ b/src/module/data.ts @@ -132,7 +132,10 @@ export const MATH_FUNCTION_NAMES: Set = new Set([ "trunc", ] as const); -type EnfolderableDocumentPF2e = ActorPF2e | ItemPF2e | Exclude; +type EnfolderableDocumentPF2e = + | ActorPF2e + | ItemPF2e + | Exclude | Item>; export { DocumentSchemaRecord, diff --git a/src/module/doc-helpers.ts b/src/module/doc-helpers.ts index bf0a7e361d9..9ef1768becc 100644 --- a/src/module/doc-helpers.ts +++ b/src/module/doc-helpers.ts @@ -5,9 +5,12 @@ import { MigrationList, MigrationRunner } from "./migration"; import { MigrationRunnerBase } from "./migration/runner/base"; /** Ensure that the import JSON is actually importable and that the data is fully migrated */ -async function preImportJSON(document: T, json: string): Promise { +async function preImportJSON( + document: TDocument, + json: string +): Promise { const source: unknown = JSON.parse(json); - if (!isObject(source)) return null; + if (!isObject(source)) return null; if ("data" in source) { if ("items" in source) { ActorPF2e.migrateData(source); @@ -31,7 +34,7 @@ async function preImportJSON(document: T, json: return null; } - const newDoc = new (document.constructor as ConstructorOf)(source, { parent: document.parent }); + const newDoc = new (document.constructor as ConstructorOf)(source, { parent: document.parent }); const migrations = MigrationList.constructFromVersion(newDoc.schemaVersion); await MigrationRunner.ensureSchemaVersion(newDoc, migrations); diff --git a/src/module/encounter/combatant.ts b/src/module/encounter/combatant.ts index 1064d4a0c27..faa8400a72d 100644 --- a/src/module/encounter/combatant.ts +++ b/src/module/encounter/combatant.ts @@ -1,12 +1,12 @@ -import type { ActorPF2e } from "@actor/base"; import { SkillLongForm } from "@actor/types"; +import { TokenDocumentPF2e } from "@scene"; import { ErrorPF2e } from "@util"; import { EncounterPF2e } from "."; class CombatantPF2e< - TParent extends EncounterPF2e | null = EncounterPF2e | null, - TActor extends ActorPF2e | null = ActorPF2e | null -> extends Combatant { + TParent extends EncounterPF2e | null, + TTokenDocument extends TokenDocumentPF2e | null = TokenDocumentPF2e | null +> extends Combatant { get encounter(): TParent { return this.parent; } @@ -36,7 +36,7 @@ class CombatantPF2e< return this.parent.getCombatantWithHigherInit(this, than) === this; } - async startTurn() { + async startTurn(): Promise { const { actor, encounter } = this; if (!encounter || !actor) return; @@ -57,7 +57,7 @@ class CombatantPF2e< Hooks.callAll("pf2e.startTurn", this, encounter, game.user.id); } - async endTurn(options: { round: number }) { + async endTurn(options: { round: number }): Promise { const round = options.round; const { actor, encounter } = this; if (!encounter || !actor) return; @@ -83,7 +83,7 @@ class CombatantPF2e< /** Toggle the defeated status of this combatant, applying or removing the overlay icon on its token */ async toggleDefeated(): Promise { await this.update({ defeated: !this.defeated }); - await this.token?.object.toggleEffect(game.settings.get("pf2e", "deathIcon"), { overlay: true }); + await this.token?.object?.toggleEffect(game.settings.get("pf2e", "deathIcon"), { overlay: true }); /** Remove this combatant's token as a target if it died */ if (this.isDefeated && this.token?.object?.isTargeted) { @@ -142,7 +142,7 @@ class CombatantPF2e< protected override _onUpdate( changed: DeepPartial, - options: DocumentUpdateContext, + options: DocumentUpdateContext, userId: string ): void { super._onUpdate(changed, options, userId); @@ -162,7 +162,7 @@ class CombatantPF2e< } } - protected override _onDelete(options: DocumentModificationContext, userId: string): void { + protected override _onDelete(options: DocumentModificationContext, userId: string): void { super._onDelete(options, userId); // Reset actor data in case initiative order changed if (this.encounter?.started) { @@ -172,22 +172,23 @@ class CombatantPF2e< } interface CombatantPF2e< - TParent extends EncounterPF2e | null = EncounterPF2e | null, - TActor extends ActorPF2e | null = ActorPF2e | null -> extends Combatant { + TParent extends EncounterPF2e | null, + TTokenDocument extends TokenDocumentPF2e | null = TokenDocumentPF2e | null +> extends Combatant { flags: CombatantFlags; } -type CombatantFlags = { +interface CombatantFlags extends DocumentFlags { pf2e: { initiativeStatistic: SkillLongForm | "perception" | null; roundOfLastTurn: number | null; roundOfLastTurnEnd: number | null; overridePriority: Record; }; - [key: string]: unknown; -}; +} -type RolledCombatant = CombatantPF2e & { get initiative(): number }; +type RolledCombatant = CombatantPF2e & { + get initiative(): number; +}; export { CombatantPF2e, CombatantFlags, RolledCombatant }; diff --git a/src/module/encounter/document.ts b/src/module/encounter/document.ts index 72b24dcb6ba..dd46c8dfe69 100644 --- a/src/module/encounter/document.ts +++ b/src/module/encounter/document.ts @@ -1,18 +1,21 @@ -import { CharacterPF2e, NPCPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e } from "@actor"; import { CharacterSheetPF2e } from "@actor/character/sheet"; import { InitiativeRollResult } from "@actor/creature"; import { RollInitiativeOptionsPF2e } from "@actor/data"; import { resetActors } from "@actor/helpers"; import { SkillLongForm } from "@actor/types"; import { SKILL_DICTIONARY, SKILL_LONG_FORMS } from "@actor/values"; -import { ScenePF2e } from "@scene"; +import { ScenePF2e, TokenDocumentPF2e } from "@scene"; import { LocalizePF2e } from "@system/localize"; import { setHasElement } from "@util"; import { CombatantFlags, CombatantPF2e, RolledCombatant } from "./combatant"; class EncounterPF2e extends Combat { /** Sort combatants by initiative rolls, falling back to tiebreak priority and then finally combatant ID (random) */ - protected override _sortCombatants(a: CombatantPF2e, b: CombatantPF2e): number { + protected override _sortCombatants( + a: CombatantPF2e, + b: CombatantPF2e + ): number { const resolveTie = (): number => { const [priorityA, priorityB] = [a, b].map( (combatant): number => @@ -37,9 +40,9 @@ class EncounterPF2e extends Combat { /** Exclude orphaned, loot-actor, and minion tokens from combat */ override async createEmbeddedDocuments( embeddedName: "Combatant", - data: PreCreate[], - context: DocumentModificationContext = {} - ): Promise[]> { + data: PreCreate[], + context: DocumentModificationContext = {} + ): Promise>[]> { const createData = data.filter((datum) => { const token = canvas.tokens.placeables.find((canvasToken) => canvasToken.id === datum.tokenId); if (!token) return false; @@ -67,18 +70,22 @@ class EncounterPF2e extends Combat { return true; }); - return super.createEmbeddedDocuments(embeddedName, createData, context) as Promise[]>; + return super.createEmbeddedDocuments(embeddedName, createData, context) as Promise< + CombatantPF2e>[] + >; } /** Roll initiative for PCs and NPCs using their prepared roll methods */ override async rollInitiative(ids: string[], options: RollInitiativeOptionsPF2e = {}): Promise { - const combatants = ids.flatMap((id) => this.combatants.get(id) ?? []) as CombatantPF2e[]; + const combatants: { id: string; actor: ActorPF2e | null }[] = ids.flatMap( + (id) => this.combatants.get(id) ?? [] + ); const fightyCombatants = combatants.filter( - (c): c is CombatantPF2e => !!c.actor?.isOfType("character", "npc") + (c): c is { id: string; actor: ActorPF2e } => !!c.actor?.isOfType("character", "npc") ); const rollResults = await Promise.all( - fightyCombatants.map((combatant): Promise => { - const checkType = combatant.actor.system.attributes.initiative.ability; + fightyCombatants.map(async (combatant): Promise => { + const checkType = combatant.actor.system.attributes.initiative?.ability ?? ""; const skills: Record = SKILL_DICTIONARY; const rollOptions = combatant.actor.getRollOptions([ "all", @@ -86,12 +93,14 @@ class EncounterPF2e extends Combat { skills[checkType] ?? checkType, ]); if (options.secret) rollOptions.push("secret"); - return combatant.actor.system.attributes.initiative.roll({ - options: rollOptions, - updateTracker: false, - skipDialog: !!options.skipDialog, - rollMode: options.messageOptions?.rollMode, - }); + return ( + combatant.actor.system.attributes.initiative?.roll?.({ + options: rollOptions, + updateTracker: false, + skipDialog: !!options.skipDialog, + rollMode: options.messageOptions?.rollMode, + }) ?? null + ); }) ); @@ -120,12 +129,12 @@ class EncounterPF2e extends Combat { async setMultipleInitiatives(initiatives: SetInitiativeData[]): Promise { const currentId = this.combatant?.id; const updates = initiatives.map( - (i): { _id: string; initiative: number; flags: { pf2e: DeepPartial } } => ({ + (i): { _id: string; initiative: number; flags: DeepPartial } => ({ _id: i.id, initiative: i.value, flags: { pf2e: { - initiativeStatistic: i.statistic, + initiativeStatistic: i.statistic ?? null, overridePriority: { [i.value]: i.overridePriority, }, @@ -153,14 +162,14 @@ class EncounterPF2e extends Combat { /** Enable the initiative button on PC sheets */ protected override _onCreate( - data: foundry.data.CombatSource, - options: DocumentModificationContext, + data: this["_source"], + options: DocumentModificationContext, userId: string ): void { super._onCreate(data, options, userId); const pcSheets = Object.values(ui.windows).filter( - (sheet): sheet is CharacterSheetPF2e => sheet instanceof CharacterSheetPF2e + (sheet): sheet is CharacterSheetPF2e => sheet instanceof CharacterSheetPF2e ); for (const sheet of pcSheets) { sheet.enableInitiativeButton(); @@ -169,8 +178,8 @@ class EncounterPF2e extends Combat { /** Call onTurnStart for each rule element on the new turn's actor */ protected override _onUpdate( - changed: DeepPartial, - options: DocumentModificationContext, + changed: DeepPartial, + options: DocumentModificationContext, userId: string ): void { super._onUpdate(changed, options, userId); @@ -222,7 +231,7 @@ class EncounterPF2e extends Combat { } /** Disable the initiative button on PC sheets if this was the only encounter */ - protected override _onDelete(options: DocumentModificationContext, userId: string): void { + protected override _onDelete(options: DocumentModificationContext, userId: string): void { super._onDelete(options, userId); if (this.started) { @@ -233,7 +242,7 @@ class EncounterPF2e extends Combat { // Disable the initiative button if this was the only encounter if (!game.combat) { const pcSheets = Object.values(ui.windows).filter( - (sheet): sheet is CharacterSheetPF2e => sheet instanceof CharacterSheetPF2e + (sheet): sheet is CharacterSheetPF2e => sheet instanceof CharacterSheetPF2e ); for (const sheet of pcSheets) { sheet.disableInitiativeButton(); @@ -248,16 +257,8 @@ class EncounterPF2e extends Combat { } } -interface EncounterPF2e { - readonly data: foundry.data.CombatData; - - turns: CombatantPF2e[]; - - get scene(): ScenePF2e | undefined; - - get combatant(): CombatantPF2e; - - readonly combatants: foundry.abstract.EmbeddedCollection>; +interface EncounterPF2e extends Combat { + readonly combatants: foundry.abstract.EmbeddedCollection>; rollNPC(options: RollInitiativeOptionsPF2e): Promise; } diff --git a/src/module/item/abc/document.ts b/src/module/item/abc/document.ts index 5a76e9de4fd..c19045f2092 100644 --- a/src/module/item/abc/document.ts +++ b/src/module/item/abc/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { FeatPF2e, ItemPF2e } from "@item"; import type { AncestrySource, AncestrySystemData } from "@item/ancestry/data"; import type { BackgroundSource, BackgroundSystemData } from "@item/background/data"; @@ -7,16 +8,16 @@ import { objectHasKey } from "@util"; import { UUIDUtils } from "@util/uuid-utils"; /** Abstract base class representing a Pathfinder (A)ncestry, (B)ackground, or (C)lass */ -abstract class ABCItemPF2e extends ItemPF2e { +abstract class ABCItemPF2e extends ItemPF2e { /** Returns all items that should also be deleted should this item be deleted */ - override getLinkedItems(): Embedded[] { + override getLinkedItems(): FeatPF2e[] { if (!this.actor || !objectHasKey(this.actor.itemTypes, this.type)) return []; const existingABCIds = this.actor.itemTypes[this.type].map((i) => i.id); return this.actor.itemTypes.feat.filter((f) => existingABCIds.includes(f.system.location ?? "")); } /** Returns items that should also be added when this item is created */ - override async createGrantedItems(options: { level?: number } = {}): Promise { + override async createGrantedItems(options: { level?: number } = {}): Promise[]> { const entries = Object.values(this.system.items); const packEntries = entries.filter((entry) => !!entry.uuid); if (!packEntries.length) return []; @@ -30,7 +31,7 @@ abstract class ABCItemPF2e extends ItemPF2e { const level = options.level ?? this.parent?.level; - return items.flatMap((item): FeatPF2e | never[] => { + return items.flatMap((item): FeatPF2e | never[] => { if (item instanceof FeatPF2e) { if (item.featType === "classfeature") { const level = entries.find((e) => item.sourceId === e.uuid)?.level ?? item.level; @@ -50,8 +51,8 @@ abstract class ABCItemPF2e extends ItemPF2e { }); } - protected logAutoChange(this: Embedded, path: string, value: string | number): void { - if (value === 0) return; + protected logAutoChange(path: string, value: string | number): void { + if (value === 0 || !this.actor) return; this.actor.system.autoChanges[path] = [ { mode: "upgrade", @@ -63,7 +64,7 @@ abstract class ABCItemPF2e extends ItemPF2e { } } -interface ABCItemPF2e extends ItemPF2e { +interface ABCItemPF2e extends ItemPF2e { readonly _source: AncestrySource | BackgroundSource | ClassSource; system: AncestrySystemData | BackgroundSystemData | ClassSystemData; } diff --git a/src/module/item/abc/sheet.ts b/src/module/item/abc/sheet.ts index 8f45c52e721..baf854eb715 100644 --- a/src/module/item/abc/sheet.ts +++ b/src/module/item/abc/sheet.ts @@ -4,7 +4,6 @@ import { ABCFeatureEntryData } from "@item/abc/data"; import { FeatType } from "@item/feat/data"; import { ItemSheetDataPF2e } from "@item/sheet/data-types"; import { LocalizePF2e } from "@system/localize"; -import { ABCItemPF2e } from "."; import { ItemSheetPF2e } from "../sheet/base"; abstract class ABCSheetPF2e extends ItemSheetPF2e { @@ -119,13 +118,13 @@ abstract class ABCSheetPF2e extends ItemSheetPF2e } } -type ABCItem = AncestryPF2e | BackgroundPF2e | ClassPF2e; - -interface ABCSheetData extends ItemSheetDataPF2e { +interface ABCSheetData extends ItemSheetDataPF2e { hasDetails: true; features: { key: string; item: FeatureSheetData }[]; } +type ABCItem = AncestryPF2e | BackgroundPF2e | ClassPF2e; + interface FeatureSheetData extends ABCFeatureEntryData { fromWorld: boolean; } diff --git a/src/module/item/abstract-effect/document.ts b/src/module/item/abstract-effect/document.ts index 48c4d4d78af..cc4d07222b6 100644 --- a/src/module/item/abstract-effect/document.ts +++ b/src/module/item/abstract-effect/document.ts @@ -5,9 +5,12 @@ import { ErrorPF2e, sluggify } from "@util"; import { EffectBadge } from "./data"; import { UUIDUtils } from "@util/uuid-utils"; import { ShowFloatyEffectParams } from "@module/canvas/token/object"; +import { ConditionSource, ConditionSystemData } from "@item/condition"; +import { EffectSource, EffectSystemData } from "@item/effect"; +import { AfflictionSource, AfflictionSystemData } from "@item/affliction"; /** Base effect type for all PF2e effects including conditions and afflictions */ -export abstract class AbstractEffectPF2e extends ItemPF2e { +abstract class AbstractEffectPF2e extends ItemPF2e { /** A normalized version of the slug that shows in roll options, removing certain prefixes */ rollOptionSlug!: string; @@ -73,7 +76,7 @@ export abstract class AbstractEffectPF2e extends ItemPF2e { const badge = this.badge; if (typeof badge?.value === "number") { const otherEffects = actor.items.filter( - (i): i is Embedded => + (i): i is AbstractEffectPF2e => i instanceof AbstractEffectPF2e && i.rollOptionSlug === this.rollOptionSlug ); const values = otherEffects @@ -87,14 +90,14 @@ export abstract class AbstractEffectPF2e extends ItemPF2e { protected override _onCreate( data: this["_source"], - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void { super._onCreate(data, options, userId); this.handleChange({ create: this }); } - protected override _onDelete(options: DocumentModificationContext, userId: string): void { + protected override _onDelete(options: DocumentModificationContext, userId: string): void { super._onDelete(options, userId); this.handleChange({ delete: { name: this._source.name } }); } @@ -125,3 +128,10 @@ export abstract class AbstractEffectPF2e extends ItemPF2e { game.pf2e.StatusEffects.refresh(); } } + +interface AbstractEffectPF2e extends ItemPF2e { + readonly _source: AfflictionSource | ConditionSource | EffectSource; + system: AfflictionSystemData | ConditionSystemData | EffectSystemData; +} + +export { AbstractEffectPF2e }; diff --git a/src/module/item/action/document.ts b/src/module/item/action/document.ts index 44195e745b8..7e717a523b3 100644 --- a/src/module/item/action/document.ts +++ b/src/module/item/action/document.ts @@ -4,8 +4,9 @@ import { UserPF2e } from "@module/user"; import { ActionCost, Frequency } from "@item/data/base"; import { ItemSummaryData } from "@item/data"; import { getActionTypeLabel } from "@util"; +import { ActorPF2e } from "@actor"; -class ActionItemPF2e extends ItemPF2e { +class ActionItemPF2e extends ItemPF2e { get actionCost(): ActionCost | null { const actionType = this.system.actionType.value || "passive"; if (actionType === "passive") return null; @@ -30,7 +31,7 @@ class ActionItemPF2e extends ItemPF2e { } override async getChatData( - this: Embedded, + this: ActionItemPF2e, htmlOptions: EnrichHTMLOptions = {} ): Promise { const systemData = this.system; @@ -42,7 +43,7 @@ class ActionItemPF2e extends ItemPF2e { protected override async _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { // In case this was copied from an actor, clear any active frequency value @@ -57,7 +58,7 @@ class ActionItemPF2e extends ItemPF2e { protected override async _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { // Normalize action data @@ -74,7 +75,7 @@ class ActionItemPF2e extends ItemPF2e { } } -interface ActionItemPF2e extends ItemPF2e { +interface ActionItemPF2e extends ItemPF2e { readonly _source: ActionItemSource; system: ActionSystemData; } diff --git a/src/module/item/affliction/document.ts b/src/module/item/affliction/document.ts index 9e44a0036c0..2a42caf93b9 100644 --- a/src/module/item/affliction/document.ts +++ b/src/module/item/affliction/document.ts @@ -1,14 +1,15 @@ +import { ActorPF2e } from "@actor"; import { AbstractEffectPF2e, EffectBadge } from "@item/abstract-effect"; import { UserPF2e } from "@module/user"; import { AfflictionFlags, AfflictionSource, AfflictionSystemData } from "./data"; -class AfflictionPF2e extends AbstractEffectPF2e { +class AfflictionPF2e extends AbstractEffectPF2e { override get badge(): EffectBadge { const label = game.i18n.format("PF2E.Item.Affliction.Stage", { stage: this.stage }); return { type: "counter", value: this.stage, label }; } - get stage() { + get stage(): number { return this.system.stage; } @@ -45,7 +46,7 @@ class AfflictionPF2e extends AbstractEffectPF2e { protected override async _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { const duration = changed.system?.duration; @@ -57,7 +58,7 @@ class AfflictionPF2e extends AbstractEffectPF2e { } } -interface AfflictionPF2e extends AbstractEffectPF2e { +interface AfflictionPF2e extends AbstractEffectPF2e { flags: AfflictionFlags; readonly _source: AfflictionSource; system: AfflictionSystemData; diff --git a/src/module/item/ancestry/document.ts b/src/module/item/ancestry/document.ts index d4c6f609ab1..f668da85cd5 100644 --- a/src/module/item/ancestry/document.ts +++ b/src/module/item/ancestry/document.ts @@ -1,4 +1,4 @@ -import { CharacterPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e } from "@actor"; import { CreatureSensePF2e } from "@actor/creature/sense"; import { CreatureTrait } from "@actor/creature/types"; import { SIZE_TO_REACH } from "@actor/creature/values"; @@ -8,7 +8,7 @@ import { Size } from "@module/data"; import { sluggify } from "@util"; import { AncestrySource, AncestrySystemData } from "./data"; -class AncestryPF2e extends ABCItemPF2e { +class AncestryPF2e extends ABCItemPF2e { get traits(): Set { return new Set(this.system.traits.value); } @@ -34,7 +34,7 @@ class AncestryPF2e extends ABCItemPF2e { } /** Include all ancestry features in addition to any with the expected location ID */ - override getLinkedItems(): Embedded[] { + override getLinkedItems(): FeatPF2e[] { if (!this.actor) return []; return Array.from( @@ -62,7 +62,7 @@ class AncestryPF2e extends ABCItemPF2e { } /** Prepare a character's data derived from their ancestry */ - override prepareActorData(this: Embedded): void { + override prepareActorData(this: AncestryPF2e): void { const { actor } = this; if (!(actor instanceof CharacterPF2e)) { console.error("PF2e System | Only a character can have an ancestry"); @@ -134,7 +134,7 @@ class AncestryPF2e extends ABCItemPF2e { } } -interface AncestryPF2e extends ABCItemPF2e { +interface AncestryPF2e extends ABCItemPF2e { readonly _source: AncestrySource; system: AncestrySystemData; } diff --git a/src/module/item/armor/document.ts b/src/module/item/armor/document.ts index 58dee140a93..231c4eb7249 100644 --- a/src/module/item/armor/document.ts +++ b/src/module/item/armor/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { AutomaticBonusProgression as ABP } from "@actor/character/automatic-bonus-progression"; import { ItemSummaryData } from "@item/data"; import { getResilientBonus, PhysicalItemHitPoints, PhysicalItemPF2e } from "@item/physical"; @@ -6,8 +7,8 @@ import { LocalizePF2e } from "@module/system/localize"; import { addSign, ErrorPF2e, setHasElement, sluggify } from "@util"; import { ArmorCategory, ArmorGroup, ArmorSource, ArmorSystemData, BaseArmorType } from "."; -class ArmorPF2e extends PhysicalItemPF2e { - override isStackableWith(item: PhysicalItemPF2e): boolean { +class ArmorPF2e extends PhysicalItemPF2e { + override isStackableWith(item: PhysicalItemPF2e): boolean { if (this.isEquipped || item.isEquipped) return false; return super.isStackableWith(item); } @@ -82,7 +83,7 @@ class ArmorPF2e extends PhysicalItemPF2e { return false; } - return this.actor.heldShield === this && this.actor.attributes.shield.raised; + return this.id === this.actor.attributes.shield.itemId && this.actor.attributes.shield.raised; } /** Generate a list of strings for use in predication */ @@ -137,7 +138,7 @@ class ArmorPF2e extends PhysicalItemPF2e { } } - override prepareActorData(): void { + override prepareActorData(this: ArmorPF2e): void { const { actor } = this; if (!actor) throw ErrorPF2e("This method may only be called from embedded items"); @@ -207,7 +208,7 @@ class ArmorPF2e extends PhysicalItemPF2e { } override async getChatData( - this: Embedded, + this: ArmorPF2e, htmlOptions: EnrichHTMLOptions = {} ): Promise { const systemData = this.system; @@ -242,7 +243,7 @@ class ArmorPF2e extends PhysicalItemPF2e { } } -interface ArmorPF2e extends PhysicalItemPF2e { +interface ArmorPF2e extends PhysicalItemPF2e { readonly _source: ArmorSource; system: ArmorSystemData; } diff --git a/src/module/item/background/document.ts b/src/module/item/background/document.ts index f697330824d..9f43b28fed9 100644 --- a/src/module/item/background/document.ts +++ b/src/module/item/background/document.ts @@ -1,14 +1,15 @@ -import { ABCItemPF2e, FeatPF2e, ItemPF2e } from "@item"; +import { ActorPF2e, CharacterPF2e } from "@actor"; +import { ABCItemPF2e, FeatPF2e } from "@item"; import { OneToFour } from "@module/data"; import { BackgroundSource, BackgroundSystemData } from "./data"; -class BackgroundPF2e extends ABCItemPF2e { +class BackgroundPF2e extends ABCItemPF2e { /** Set a skill feat granted by a GrantItem RE as one of this background's configured items */ - override prepareSiblingData(this: Embedded): void { + override prepareSiblingData(this: BackgroundPF2e): void { if (Object.keys(this.system.items).length > 0) return; const grantedSkillFeat = Object.values(this.flags.pf2e.itemGrants) .flatMap((g) => this.actor.items.get(g.id) ?? []) - .find((i: Embedded & { featType?: unknown }): i is Embedded => i.featType === "skill"); + .find((i): i is FeatPF2e => i.isOfType("feat") && i.featType === "skill"); if (grantedSkillFeat) { this.system.items["GRANT"] = { @@ -21,7 +22,7 @@ class BackgroundPF2e extends ABCItemPF2e { } } - override prepareActorData(this: Embedded): void { + override prepareActorData(this: BackgroundPF2e): void { if (!this.actor.isOfType("character")) { console.error("Only a character can have a background"); return; @@ -47,7 +48,7 @@ class BackgroundPF2e extends ABCItemPF2e { } } -interface BackgroundPF2e extends ABCItemPF2e { +interface BackgroundPF2e extends ABCItemPF2e { readonly _source: BackgroundSource; system: BackgroundSystemData; } diff --git a/src/module/item/base.ts b/src/module/item/base.ts index c1fef4d7489..f6c7deb8fe2 100644 --- a/src/module/item/base.ts +++ b/src/module/item/base.ts @@ -24,9 +24,10 @@ import { PhysicalItemPF2e } from "./physical/document"; import { PHYSICAL_ITEM_TYPES } from "./physical/values"; import { ItemSheetPF2e } from "./sheet/base"; import { ItemFlagsPF2e, ItemSystemData } from "./data/base"; +import { ItemInstances } from "./types"; /** Override and extend the basic :class:`Item` implementation */ -class ItemPF2e extends Item { +class ItemPF2e extends Item { /** Prepared rule elements from this item */ rules!: RuleElementPF2e[]; @@ -50,24 +51,32 @@ class ItemPF2e extends Item { } /** The item that granted this item, if any */ - get grantedBy(): Embedded | null { + get grantedBy(): ItemPF2e | null { return this.actor?.items.get(this.flags.pf2e.grantedBy?.id ?? "") ?? null; } /** Check this item's type (or whether it's one among multiple types) without a call to `instanceof` */ - isOfType(...types: T[]): this is InstanceType; - isOfType(type: "physical"): this is PhysicalItemPF2e; + isOfType(...types: T[]): this is ItemInstances[T]; + isOfType(type: "physical"): this is PhysicalItemPF2e; isOfType( ...types: T[] - ): this is PhysicalItemPF2e | InstanceType]>; + ): this is T extends "physical" + ? PhysicalItemPF2e + : T extends ItemType + ? ItemInstances[T] + : never; isOfType(...types: string[]): boolean { return types.some((t) => (t === "physical" ? setHasElement(PHYSICAL_ITEM_TYPES, this.type) : this.type === t)); } /** Redirect the deletion of any owned items to ActorPF2e#deleteEmbeddedDocuments for a single workflow */ - override async delete(context: DocumentModificationContext = {}): Promise { + override async delete(context: DocumentModificationContext = {}): Promise { if (this.actor) { - await this.actor.deleteEmbeddedDocuments("Item", [this.id], context); + await this.actor.deleteEmbeddedDocuments( + "Item", + [this.id], + context as DocumentModificationContext> + ); return this; } return super.delete(context); @@ -143,7 +152,7 @@ class ItemPF2e extends Item { }; // Basic chat message data - const chatData: PreCreate = { + const chatData: PreCreate = { speaker: ChatMessagePF2e.getSpeaker({ actor: this.actor, token: this.actor.getActiveTokens(false, true)[0] ?? null, @@ -217,12 +226,10 @@ class ItemPF2e extends Item { } } - prepareRuleElements(options?: RuleElementOptions): RuleElementPF2e[] { + prepareRuleElements(this: ItemPF2e, options?: RuleElementOptions): RuleElementPF2e[] { if (!this.actor) throw ErrorPF2e("Rule elements may only be prepared from embedded items"); - return (this.rules = this.actor.canHostRuleElements - ? RuleElements.fromOwnedItem(this as Embedded, options) - : []); + return (this.rules = this.actor.canHostRuleElements ? RuleElements.fromOwnedItem(this, options) : []); } /** Pull the latest system data from the source compendium and replace this item's with it */ @@ -337,18 +344,35 @@ class ItemPF2e extends Item { } /** Don't allow the user to create a condition or spellcasting entry from the sidebar. */ + static override createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; static override async createDialog( data: { folder?: string } = {}, - options: Partial = {} - ): Promise { + options: { + parent?: Actor | null> | null; + pack?: Collection> | null; + } & Partial = {} + ): Promise | null> | null> | null> { const original = game.system.documentTypes.Item; game.system.documentTypes.Item = original.filter( (itemType: string) => !["condition", "spellcastingEntry", "lore"].includes(itemType) && !(["affliction", "book"].includes(itemType) && BUILD_MODE === "production") ); - options = { ...options, classes: [...(options.classes ?? []), "dialog-item-create"] }; - const newItem = super.createDialog(data, options) as Promise; + const withClasses: { + parent?: Actor | null> | null; + pack?: Collection | null> | null>> | null; + } & Partial = { + ...options, + classes: [...(options.classes ?? []), "dialog-item-create"], + }; + const newItem = super.createDialog(data, withClasses); game.system.documentTypes.Item = original; return newItem; } @@ -364,15 +388,15 @@ class ItemPF2e extends Item { return { ...super.toDragData(), itemType: this.type }; } - static override async createDocuments( - this: ConstructorOf, - data?: (T | PreCreate)[], - context?: DocumentModificationContext - ): Promise; + static override async createDocuments( + this: ConstructorOf, + data?: (TDocument | PreCreate)[], + context?: DocumentModificationContext + ): Promise; static override async createDocuments( data: (ItemPF2e | PreCreate)[] = [], - context: DocumentModificationContext = {} - ): Promise { + context: DocumentModificationContext = {} + ): Promise | null> | null>[]> { // Convert all `ItemPF2e`s to source objects const sources = data.map((d) => (d instanceof ItemPF2e ? d.toObject() : d)); @@ -432,32 +456,34 @@ class ItemPF2e extends Item { // actor.deleteEmbeddedDocuments() will also delete any linked items. const singularTypes = ["ancestry", "background", "class", "heritage", "deity"] as const; const singularTypesToDelete = singularTypes.filter((type) => sources.some((s) => s.type === type)); - const preCreateDeletions = singularTypesToDelete.flatMap((type): Embedded[] => actor.itemTypes[type]); + const preCreateDeletions = singularTypesToDelete.flatMap( + (type): ItemPF2e[] => actor.itemTypes[type] + ); if (preCreateDeletions.length) { const idsToDelete = preCreateDeletions.map((i) => i.id); await actor.deleteEmbeddedDocuments("Item", idsToDelete, { render: false }); } // Convert all non-kit sources to item objects, and recursively extract the simple grants from ABC items - const items = await (async () => { + const items = await (async (): Promise[]> => { /** Internal function to recursively get all simple granted items */ - async function getSimpleGrants(item: Embedded): Promise[]> { + async function getSimpleGrants(item: ItemPF2e): Promise[]> { const granted = (await item.createGrantedItems?.({ size: context.parent?.size })) ?? []; if (!granted.length) return []; const reparented = granted.map( - (i): Embedded => + (i): ItemPF2e => (i.parent ? i - : new CONFIG.Item.documentClass(i._source, { parent: actor })) as Embedded + : new CONFIG.Item.documentClass(i._source, { parent: actor })) as ItemPF2e ); return [...reparented, ...(await Promise.all(reparented.map(getSimpleGrants))).flat()]; } - const items = sources.map((source): Embedded => { + const items = sources.map((source): ItemPF2e => { if (!(context.keepId || context.keepEmbeddedIds)) { source._id = randomID(); } - return new CONFIG.Item.documentClass(source, { parent: actor }) as Embedded; + return new CONFIG.Item.documentClass(source, { parent: actor }) as ItemPF2e; }); // If any item we plan to add will add new items (such as ABC items), add those too @@ -507,18 +533,22 @@ class ItemPF2e extends Item { return super.createDocuments(nonKits, context); } - static override async deleteDocuments>( - this: T, + static override async deleteDocuments( + this: ConstructorOf, + ids?: string[], + context?: DocumentModificationContext + ): Promise; + static override async deleteDocuments( ids: string[] = [], - context: DocumentModificationContext> = {} - ): Promise[]> { + context: DocumentModificationContext = {} + ): Promise | null> | null>[]> { ids = Array.from(new Set(ids)); const actor = context.parent; if (actor) { const items = ids.flatMap((id) => actor.items.get(id) ?? []); // If a container is being deleted, its contents need to have their containerId references updated - const containers = items.filter((i): i is Embedded => i.isOfType("backpack")); + const containers = items.filter((i): i is ContainerPF2e => i.isOfType("backpack")); for (const container of containers) { await container.ejectContents(); } @@ -534,7 +564,7 @@ class ItemPF2e extends Item { ids = Array.from(new Set(items.map((i) => i.id))).filter((id) => actor.items.has(id)); } - return super.deleteDocuments(ids, context) as Promise[]>; + return super.deleteDocuments(ids, context); } /* -------------------------------------------- */ @@ -543,7 +573,7 @@ class ItemPF2e extends Item { protected override async _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { // Set default icon @@ -575,7 +605,7 @@ class ItemPF2e extends Item { /** Keep `TextEditor` and anything else up to no good from setting this item's description to `null` */ protected override async _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentUpdateContext, user: UserPF2e ): Promise { if (changed.system?.description?.value === null) { @@ -615,7 +645,7 @@ class ItemPF2e extends Item { /** Call onCreate rule-element hooks */ protected override _onCreate( data: ItemSourcePF2e, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void { super._onCreate(data, options, userId); @@ -634,7 +664,7 @@ class ItemPF2e extends Item { } /** Call onDelete rule-element hooks */ - protected override _onDelete(options: DocumentModificationContext, userId: string): void { + protected override _onDelete(options: DocumentModificationContext, userId: string): void { super._onDelete(options, userId); if (!(this.actor && game.user.id === userId)) return; @@ -646,7 +676,7 @@ class ItemPF2e extends Item { if (this.actor.isOfType("npc") && ["action", "consumable"].includes(this.type)) { const slug = this.slug ?? sluggify(this.name); if (!this.actor.isToken) { - const itemUpdates: DocumentUpdateData[] = []; + const itemUpdates: DocumentUpdateData[] = []; for (const attack of this.actor.itemTypes.melee) { const attackEffects = attack.system.attackEffects.value; if (attackEffects.includes(slug)) { @@ -662,7 +692,7 @@ class ItemPF2e extends Item { } } else { // The above method of updating embedded items in an actor update does not work with synthetic actors - const promises: Promise[] = []; + const promises: Promise>[] = []; for (const item of this.actor.itemTypes.melee) { const attackEffects = item.system.attackEffects.value; if (attackEffects.includes(slug)) { @@ -684,31 +714,30 @@ class ItemPF2e extends Item { } } -interface ItemPF2e extends Item { +interface ItemPF2e extends Item { flags: ItemFlagsPF2e; readonly _source: ItemSourcePF2e; - readonly parent: ActorPF2e | null; system: ItemSystemData; _sheet: ItemSheetPF2e | null; get sheet(): ItemSheetPF2e; - prepareSiblingData?(this: Embedded): void; - prepareActorData?(this: Embedded): void; + prepareSiblingData?(this: ItemPF2e): void; + prepareActorData?(this: ItemPF2e): void; /** Returns items that should also be added when this item is created */ - createGrantedItems?(options?: object): Promise; + createGrantedItems(options?: object): Promise; /** Returns items that should also be deleted should this item be deleted */ - getLinkedItems?(): Embedded[]; + getLinkedItems?(): ItemPF2e[]; } /** A `Proxy` to to get Foundry to construct `ItemPF2e` subclasses */ const ItemProxyPF2e = new Proxy(ItemPF2e, { construct( _target, - args: [source: PreCreate, context: DocumentConstructionContext] + args: [source: PreCreate, context?: DocumentConstructionContext] ) { return new CONFIG.PF2E.Item.documentClasses[args[0].type](...args); }, diff --git a/src/module/item/book/document.ts b/src/module/item/book/document.ts index 6d074aef9a4..314f0265f4f 100644 --- a/src/module/item/book/document.ts +++ b/src/module/item/book/document.ts @@ -1,9 +1,10 @@ +import { ActorPF2e } from "@actor"; import { PhysicalItemPF2e } from "@item"; import { BookSource, BookSystemData } from "./data"; -class BookPF2e extends PhysicalItemPF2e {} +class BookPF2e extends PhysicalItemPF2e {} -interface BookPF2e extends PhysicalItemPF2e { +interface BookPF2e extends PhysicalItemPF2e { readonly _source: BookSource; system: BookSystemData; } diff --git a/src/module/item/class/document.ts b/src/module/item/class/document.ts index 860c647babe..fcf6d889dfe 100644 --- a/src/module/item/class/document.ts +++ b/src/module/item/class/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e, CharacterPF2e } from "@actor"; import { ClassDCData } from "@actor/character/data"; import { FeatSlotLevel } from "@actor/character/feats"; import { SaveType } from "@actor/types"; @@ -10,7 +11,7 @@ import { ZeroToFour } from "@module/data"; import { setHasElement, sluggify } from "@util"; import { ClassAttackProficiencies, ClassDefenseProficiencies, ClassSource, ClassSystemData, ClassTrait } from "./data"; -class ClassPF2e extends ABCItemPF2e { +class ClassPF2e extends ABCItemPF2e { get attacks(): ClassAttackProficiencies { return this.system.attacks; } @@ -57,24 +58,25 @@ class ClassPF2e extends ABCItemPF2e { } /** Include all top-level class features in addition to any with the expected location ID */ - override getLinkedItems(): Embedded[] { - if (!this.actor) return []; + override getLinkedItems(): FeatPF2e[] { + const { actor } = this; + if (!actor) return []; return Array.from( new Set([ ...super.getLinkedItems(), - ...this.actor.itemTypes.feat.filter( + ...actor.itemTypes.feat.filter( (f) => f.featType === "classfeature" && - !(f.flags.pf2e.grantedBy && this.actor?.items.has(f.flags.pf2e.grantedBy.id)) + !(f.flags.pf2e.grantedBy && actor.items.has(f.flags.pf2e.grantedBy.id)) ), ]) ); } /** Pulls the features that should be granted by this class, sorted by level and choice set */ - override async createGrantedItems(options: { level?: number } = {}): Promise { - const hasChoiceSet = (f: FeatPF2e) => f.system.rules.some((re) => re.key === "ChoiceSet"); + override async createGrantedItems(options: { level?: number } = {}): Promise[]> { + const hasChoiceSet = (f: FeatPF2e) => f.system.rules.some((re) => re.key === "ChoiceSet"); return (await super.createGrantedItems(options)).sort((a, b) => { const [aLevel, bLevel] = [a.system.level.value, b.system.level.value]; if (aLevel !== bLevel) return aLevel - bLevel; @@ -92,8 +94,8 @@ class ClassPF2e extends ABCItemPF2e { } /** Prepare a character's data derived from their class */ - override prepareActorData(this: Embedded): void { - if (!this.actor.isOfType("character")) { + override prepareActorData(this: ClassPF2e): void { + if (!this.actor?.isOfType("character")) { console.error("Only a character can have a class"); return; } @@ -158,7 +160,7 @@ class ClassPF2e extends ABCItemPF2e { } } -interface ClassPF2e extends ABCItemPF2e { +interface ClassPF2e extends ABCItemPF2e { readonly _source: ClassSource; system: ClassSystemData; diff --git a/src/module/item/condition/data.ts b/src/module/item/condition/data.ts index 6e967da941b..70d78d2986a 100644 --- a/src/module/item/condition/data.ts +++ b/src/module/item/condition/data.ts @@ -21,6 +21,7 @@ interface ConditionSystemSource extends ItemSystemSource { group: string | null; value: ConditionValueData; overrides: string[]; + context?: never; level?: never; traits?: never; } diff --git a/src/module/item/condition/document.ts b/src/module/item/condition/document.ts index 2c7671a84e0..98ad967136d 100644 --- a/src/module/item/condition/document.ts +++ b/src/module/item/condition/document.ts @@ -13,7 +13,7 @@ import { Statistic } from "@system/statistic"; import { ErrorPF2e } from "@util"; import { ConditionKey, ConditionSlug, ConditionSource, ConditionSystemData, PersistentDamageData } from "./data"; -class ConditionPF2e extends AbstractEffectPF2e { +class ConditionPF2e extends AbstractEffectPF2e { active!: boolean; override get badge(): EffectBadge | null { @@ -35,7 +35,7 @@ class ConditionPF2e extends AbstractEffectPF2e { return this.system.persistent ? `persistent-damage-${this.system.persistent.damageType}` : this.slug; } - get appliedBy(): ItemPF2e | null { + get appliedBy(): ItemPF2e | null { return this.actor?.items.get(this.system.references.parent?.id ?? this.flags.pf2e.grantedBy?.id ?? "") ?? null; } @@ -70,12 +70,12 @@ class ConditionPF2e extends AbstractEffectPF2e { return options; } - override async increase(): Promise { - await this.actor?.increaseCondition(this as Embedded); + override async increase(this: ConditionPF2e): Promise { + await this.actor?.increaseCondition(this); } - override async decrease(): Promise { - await this.actor?.decreaseCondition(this as Embedded); + override async decrease(this: ConditionPF2e): Promise { + await this.actor?.decreaseCondition(this); } async onEndTurn(options: { token?: TokenDocumentPF2e | null } = {}): Promise { @@ -160,7 +160,7 @@ class ConditionPF2e extends AbstractEffectPF2e { // Inactive conditions shouldn't deactivate others if (!this.active) return; - const deactivate = (condition: ConditionPF2e): void => { + const deactivate = (condition: ConditionPF2e): void => { condition.active = false; condition.system.references.overriddenBy.push({ id: this.id, type: "condition" as const }); }; @@ -194,7 +194,7 @@ class ConditionPF2e extends AbstractEffectPF2e { } /** Log self in parent's conditions map */ - override prepareActorData(): void { + override prepareActorData(this: ConditionPF2e): void { super.prepareActorData(); if (this.active) { @@ -213,7 +213,7 @@ class ConditionPF2e extends AbstractEffectPF2e { protected override async _preUpdate( changed: DeepPartial, - options: ConditionModificationContext, + options: ConditionModificationContext, user: UserPF2e ): Promise { options.conditionValue = this.value; @@ -222,7 +222,7 @@ class ConditionPF2e extends AbstractEffectPF2e { protected override _onUpdate( changed: DeepPartial, - options: ConditionModificationContext, + options: ConditionModificationContext, userId: string ): void { super._onUpdate(changed, options, userId); @@ -244,18 +244,18 @@ class ConditionPF2e extends AbstractEffectPF2e { } } -interface ConditionPF2e extends AbstractEffectPF2e { +interface ConditionPF2e extends AbstractEffectPF2e { readonly _source: ConditionSource; system: ConditionSystemData; get slug(): ConditionSlug; } -interface PersistentDamagePF2e extends ConditionPF2e { +interface PersistentDamagePF2e extends ConditionPF2e { system: Omit & { persistent: PersistentDamageData }; } -interface ConditionModificationContext extends DocumentModificationContext { +interface ConditionModificationContext extends DocumentModificationContext { conditionValue?: number | null; } diff --git a/src/module/item/condition/persistent-damage-dialog.ts b/src/module/item/condition/persistent-damage-dialog.ts index 741afa7350a..3a9b8d74665 100644 --- a/src/module/item/condition/persistent-damage-dialog.ts +++ b/src/module/item/condition/persistent-damage-dialog.ts @@ -33,7 +33,7 @@ class PersistentDamageDialog extends Application { override async getData(): Promise { const existing = this.actor.itemTypes.condition - .filter((c): c is Embedded => c.slug === "persistent-damage") + .filter((c): c is PersistentDamagePF2e => c.slug === "persistent-damage") .map((c) => ({ id: c.id, bullet: damageDiceIcon(c.system.persistent.damage).outerHTML, @@ -112,7 +112,7 @@ class PersistentDamageDialog extends Application { html.querySelector("[data-action=roll-persistent]")?.addEventListener("click", () => { const existing = this.actor.itemTypes.condition.filter( - (c): c is Embedded => c.slug === "persistent-damage" + (c): c is PersistentDamagePF2e => c.slug === "persistent-damage" ); for (const condition of existing) { diff --git a/src/module/item/consumable/document.ts b/src/module/item/consumable/document.ts index 1b5d2a7af06..0f88201f8e7 100644 --- a/src/module/item/consumable/document.ts +++ b/src/module/item/consumable/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { TrickMagicItemPopup } from "@actor/sheet/trick-magic-item-popup"; import { ItemPF2e, PhysicalItemPF2e, SpellcastingEntryPF2e, SpellPF2e, WeaponPF2e } from "@item"; import { ItemSummaryData } from "@item/data"; @@ -9,7 +10,7 @@ import { ErrorPF2e } from "@util"; import { ConsumableCategory, ConsumableSystemData, ConsumableSource } from "./data"; import { OtherConsumableTag } from "./types"; -class ConsumablePF2e extends PhysicalItemPF2e { +class ConsumablePF2e extends PhysicalItemPF2e { get otherTags(): Set { return new Set(this.system.traits.otherTags); } @@ -34,14 +35,14 @@ class ConsumablePF2e extends PhysicalItemPF2e { return this.system.autoDestroy.value; } - get embeddedSpell(): Embedded | null { + get embeddedSpell(): SpellPF2e | null { if (!this.actor) throw ErrorPF2e(`No owning actor found for "${this.name}" (${this.id})`); if (!this.system.spell) return null; return new SpellPF2e(deepClone(this.system.spell), { parent: this.actor, fromConsumable: true, - }) as Embedded; + }) as SpellPF2e; } get formula(): string | null { @@ -77,7 +78,7 @@ class ConsumablePF2e extends PhysicalItemPF2e { } override async getChatData( - this: Embedded, + this: ConsumablePF2e, htmlOptions: EnrichHTMLOptions = {}, rollOptions: Record = {} ): Promise { @@ -147,7 +148,7 @@ class ConsumablePF2e extends PhysicalItemPF2e { } /** Use a consumable item, sending the result to chat */ - async consume(this: Embedded): Promise { + async consume(this: ConsumablePF2e): Promise { const { value, max } = this.uses; if (["scroll", "wand"].includes(this.category) && this.system.spell) { @@ -217,7 +218,7 @@ class ConsumablePF2e extends PhysicalItemPF2e { } } - async castEmbeddedSpell(this: Embedded, trickMagicItemData?: TrickMagicItemEntry): Promise { + async castEmbeddedSpell(this: ConsumablePF2e, trickMagicItemData?: TrickMagicItemEntry): Promise { const spell = this.embeddedSpell; if (!spell) return; const actor = this.actor; @@ -227,7 +228,7 @@ class ConsumablePF2e extends PhysicalItemPF2e { if (trickMagicItemData) return trickMagicItemData; return actor.spellcasting .filter( - (e): e is SpellcastingEntryPF2e => + (e): e is SpellcastingEntryPF2e => e instanceof SpellcastingEntryPF2e && e.canCast(spell, { origin: this }) ) .reduce((previous, current) => { @@ -248,7 +249,7 @@ class ConsumablePF2e extends PhysicalItemPF2e { } } -interface ConsumablePF2e extends PhysicalItemPF2e { +interface ConsumablePF2e extends PhysicalItemPF2e { readonly _source: ConsumableSource; system: ConsumableSystemData; } diff --git a/src/module/item/container/document.ts b/src/module/item/container/document.ts index 106febabaac..6073cb00db9 100644 --- a/src/module/item/container/document.ts +++ b/src/module/item/container/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { InventoryBulk } from "@actor/inventory"; import { ItemSummaryData } from "@item/data"; import { EquipmentTrait } from "@item/equipment/data"; @@ -6,9 +7,9 @@ import { Bulk, weightToBulk } from "@item/physical/bulk"; import { ContainerSource, ContainerSystemData } from "./data"; import { hasExtraDimensionalParent } from "./helpers"; -class ContainerPF2e extends PhysicalItemPF2e { +class ContainerPF2e extends PhysicalItemPF2e { /** This container's contents, reloaded every data preparation cycle */ - contents: Collection> = new Collection(); + contents: Collection>> = new Collection(); /** Is this an actual stowing container or merely one of the old pouches/quivers/etc.? */ get stowsItems(): boolean { @@ -38,9 +39,9 @@ class ContainerPF2e extends PhysicalItemPF2e { } /** Reload this container's contents following Actor embedded-document preparation */ - override prepareSiblingData(this: Embedded): void { + override prepareSiblingData(this: ContainerPF2e): void { this.contents = new Collection( - this.actor.inventory.filter((item) => item.container?.id === this.id).map((item) => [item.id, item]) + this.actor.inventory.filter((i) => i.container?.id === this.id).map((item) => [item.id, item]) ); } @@ -53,7 +54,7 @@ class ContainerPF2e extends PhysicalItemPF2e { } override async getChatData( - this: Embedded, + this: ContainerPF2e, htmlOptions: EnrichHTMLOptions = {} ): Promise { return this.processChatData(htmlOptions, { @@ -63,7 +64,7 @@ class ContainerPF2e extends PhysicalItemPF2e { } } -interface ContainerPF2e extends PhysicalItemPF2e { +interface ContainerPF2e extends PhysicalItemPF2e { readonly _source: ContainerSource; system: ContainerSystemData; diff --git a/src/module/item/container/helpers.ts b/src/module/item/container/helpers.ts index 8a591bf69b8..d6d1a23862c 100644 --- a/src/module/item/container/helpers.ts +++ b/src/module/item/container/helpers.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ContainerPF2e, PhysicalItemPF2e } from "@item"; /** @@ -5,7 +6,7 @@ import { ContainerPF2e, PhysicalItemPF2e } from "@item"; * @param item The item being added to a container * @param container The container to which the item is being added */ -export function isCycle(item: PhysicalItemPF2e, container: Embedded): boolean { +export function isCycle(item: PhysicalItemPF2e, container: ContainerPF2e): boolean { if (item === container) return true; if (container.container) return isCycle(item, container.container); return false; diff --git a/src/module/item/data/base.ts b/src/module/item/data/base.ts index 4477ab9ccdd..77c5de60079 100644 --- a/src/module/item/data/base.ts +++ b/src/module/item/data/base.ts @@ -7,7 +7,7 @@ import { ItemType } from "."; import { PhysicalItemTrait } from "../physical/data"; interface BaseItemSourcePF2e - extends foundry.data.ItemSource { + extends foundry.documents.ItemSource { flags: ItemSourceFlagsPF2e; } diff --git a/src/module/item/deity/document.ts b/src/module/item/deity/document.ts index 6e9f1ed227e..de84057a084 100644 --- a/src/module/item/deity/document.ts +++ b/src/module/item/deity/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e, CharacterPF2e } from "@actor"; import { Alignment } from "@actor/creature/types"; import { ALIGNMENTS } from "@actor/creature/values"; import { ItemPF2e } from "@item"; @@ -5,7 +6,7 @@ import { BaseWeaponType } from "@item/weapon/types"; import { sluggify } from "@util"; import { DeitySource, DeitySystemData } from "./data"; -class DeityPF2e extends ItemPF2e { +class DeityPF2e extends ItemPF2e { get category(): "deity" | "pantheon" | "philosophy" { return this.system.category; } @@ -30,14 +31,14 @@ class DeityPF2e extends ItemPF2e { } } - override prepareActorData(this: Embedded): void { + override prepareActorData(this: DeityPF2e): void { if (!this.actor.isOfType("character")) { // This should never happen, but ... this.delete({ render: false }); return; } - this.actor.deity = this; + this.actor.deity = this as DeityPF2e; const { deities } = this.actor.system.details; const systemData = this.system; @@ -80,7 +81,7 @@ class DeityPF2e extends ItemPF2e { } /** If applicable, set a trained proficiency with this deity's favored weapon */ - setFavoredWeaponRank(this: Embedded): void { + setFavoredWeaponRank(this: DeityPF2e): void { if (!this.actor.isOfType("character")) return; const favoredWeaponRank = this.actor.flags.pf2e.favoredWeaponRank; @@ -103,7 +104,7 @@ class DeityPF2e extends ItemPF2e { } } -interface DeityPF2e extends ItemPF2e { +interface DeityPF2e extends ItemPF2e { readonly _source: DeitySource; system: DeitySystemData; } diff --git a/src/module/item/effect/document.ts b/src/module/item/effect/document.ts index d96b52321c0..665a758d15c 100644 --- a/src/module/item/effect/document.ts +++ b/src/module/item/effect/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { AbstractEffectPF2e } from "@item/abstract-effect"; import { EffectBadge } from "@item/abstract-effect/data"; import { ChatMessagePF2e } from "@module/chat-message"; @@ -6,7 +7,7 @@ import { UserPF2e } from "@module/user"; import { isObject, objectHasKey, sluggify } from "@util"; import { EffectFlags, EffectSource, EffectSystemData } from "./data"; -class EffectPF2e extends AbstractEffectPF2e { +class EffectPF2e extends AbstractEffectPF2e { static DURATION_UNITS: Readonly> = { rounds: 6, minutes: 60, @@ -150,7 +151,7 @@ class EffectPF2e extends AbstractEffectPF2e { /** Set the start time and initiative roll of a newly created effect */ protected override async _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { if (this.isOwned) { @@ -180,7 +181,7 @@ class EffectPF2e extends AbstractEffectPF2e { protected override async _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { const duration = changed.system?.duration; @@ -200,15 +201,15 @@ class EffectPF2e extends AbstractEffectPF2e { return super._preUpdate(changed, options, user); } - protected override _onDelete(options: DocumentModificationContext, userId: string): void { + protected override _onDelete(options: DocumentModificationContext, userId: string): void { if (this.actor) { - game.pf2e.effectTracker.unregister(this as Embedded); + game.pf2e.effectTracker.unregister(this as EffectPF2e); } super._onDelete(options, userId); } } -interface EffectPF2e extends AbstractEffectPF2e { +interface EffectPF2e extends AbstractEffectPF2e { flags: EffectFlags; readonly _source: EffectSource; system: EffectSystemData; diff --git a/src/module/item/equipment/document.ts b/src/module/item/equipment/document.ts index a13f8701f4d..fa8ebc817e6 100644 --- a/src/module/item/equipment/document.ts +++ b/src/module/item/equipment/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ItemSummaryData } from "@item/data"; import { PhysicalItemPF2e } from "@item/physical"; import { LocalizePF2e } from "@module/system/localize"; @@ -5,7 +6,7 @@ import { objectHasKey, sluggify } from "@util"; import { EquipmentSource, EquipmentSystemData, EquipmentTrait } from "./data"; import { OtherEquipmentTag } from "./types"; -class EquipmentPF2e extends PhysicalItemPF2e { +class EquipmentPF2e extends PhysicalItemPF2e { get otherTags(): Set { return new Set(this.system.traits.otherTags); } @@ -27,7 +28,7 @@ class EquipmentPF2e extends PhysicalItemPF2e { } override async getChatData( - this: Embedded, + this: EquipmentPF2e, htmlOptions: EnrichHTMLOptions = {} ): Promise { return this.processChatData(htmlOptions, { @@ -55,7 +56,7 @@ class EquipmentPF2e extends PhysicalItemPF2e { } } -interface EquipmentPF2e extends PhysicalItemPF2e { +interface EquipmentPF2e extends PhysicalItemPF2e { readonly _source: EquipmentSource; system: EquipmentSystemData; diff --git a/src/module/item/feat/document.ts b/src/module/item/feat/document.ts index 7b7975209ba..6731fb20ecb 100644 --- a/src/module/item/feat/document.ts +++ b/src/module/item/feat/document.ts @@ -6,8 +6,9 @@ import { getActionTypeLabel, sluggify } from "@util"; import { FeatCategory } from "@actor/character/feats"; import { Frequency } from "@item/data/base"; import { ItemSummaryData } from "@item/data"; +import { ActorPF2e } from "@actor"; -class FeatPF2e extends ItemPF2e { +class FeatPF2e extends ItemPF2e { category!: FeatCategory | null; get featType(): FeatType { @@ -105,14 +106,14 @@ class FeatPF2e extends ItemPF2e { } /** Set a self roll option for this feat(ure) */ - override prepareActorData(this: Embedded): void { + override prepareActorData(this: FeatPF2e): void { const prefix = this.isFeature ? "feature" : "feat"; const slug = this.slug ?? sluggify(this.name); this.actor.rollOptions.all[`${prefix}:${slug}`] = true; } override async getChatData( - this: Embedded, + this: FeatPF2e, htmlOptions: EnrichHTMLOptions = {} ): Promise { const levelLabel = game.i18n.format("PF2E.LevelN", { level: this.level }); @@ -139,7 +140,7 @@ class FeatPF2e extends ItemPF2e { protected override async _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { // In case this was copied from an actor, clear the location if there's no parent. @@ -155,7 +156,7 @@ class FeatPF2e extends ItemPF2e { protected override async _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { // Ensure an empty-string `location` property is null @@ -196,7 +197,11 @@ class FeatPF2e extends ItemPF2e { } /** Warn the owning user(s) if this feat was taken despite some restriction */ - protected override _onCreate(data: FeatSource, options: DocumentModificationContext, userId: string): void { + protected override _onCreate( + data: FeatSource, + options: DocumentModificationContext, + userId: string + ): void { super._onCreate(data, options, userId); if (!(this.isOwner && this.actor?.isOfType("character") && this.isFeat)) return; @@ -224,7 +229,7 @@ class FeatPF2e extends ItemPF2e { } } -interface FeatPF2e extends ItemPF2e { +interface FeatPF2e extends ItemPF2e { readonly _source: FeatSource; system: FeatSystemData; } diff --git a/src/module/item/feat/sheet.ts b/src/module/item/feat/sheet.ts index 9a66aaecd22..e73bb4e9604 100644 --- a/src/module/item/feat/sheet.ts +++ b/src/module/item/feat/sheet.ts @@ -1,7 +1,7 @@ import { FeatPF2e } from "@item/feat"; -import { FeatSheetData } from "../sheet/data-types"; import { ItemSheetPF2e } from "../sheet/base"; import Tagify from "@yaireo/tagify"; +import { ItemSheetDataPF2e } from "@item/sheet/data-types"; export class FeatSheetPF2e extends ItemSheetPF2e { override get validTraits(): Record { @@ -60,3 +60,16 @@ export class FeatSheetPF2e extends ItemSheetPF2e { return super._updateObject(event, formData); } } + +interface FeatSheetData extends ItemSheetDataPF2e { + featTypes: ConfigPF2e["PF2E"]["featTypes"]; + actionTypes: ConfigPF2e["PF2E"]["actionTypes"]; + actionsNumber: ConfigPF2e["PF2E"]["actionsNumber"]; + frequencies: ConfigPF2e["PF2E"]["frequencies"]; + damageTypes: ConfigPF2e["PF2E"]["damageTypes"] & ConfigPF2e["PF2E"]["healingTypes"]; + categories: ConfigPF2e["PF2E"]["actionCategories"]; + prerequisites: string; + isFeat: boolean; + mandatoryTakeOnce: boolean; + hasLineageTrait: boolean; +} diff --git a/src/module/item/heritage/document.ts b/src/module/item/heritage/document.ts index 6e30cbd3438..a8cad345020 100644 --- a/src/module/item/heritage/document.ts +++ b/src/module/item/heritage/document.ts @@ -1,11 +1,11 @@ -import { CharacterPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e } from "@actor"; import { CreatureTrait } from "@actor/creature"; import { ItemPF2e } from "@item"; import { Rarity } from "@module/data"; -import { sluggify } from "@util"; +import { ErrorPF2e, sluggify } from "@util"; import { HeritageSource, HeritageSystemData } from "./data"; -class HeritagePF2e extends ItemPF2e { +class HeritagePF2e extends ItemPF2e { get traits(): Set { return new Set(this.system.traits.value); } @@ -15,11 +15,12 @@ class HeritagePF2e extends ItemPF2e { } /** Prepare a character's data derived from their heritage */ - override prepareActorData(this: Embedded): void { + override prepareActorData(this: HeritagePF2e): void { + if (!this.actor.isOfType("character")) throw ErrorPF2e("heritage embedded on non-character"); // Some abilities allow for a second heritage. If the PC has more than one, set this heritage as the actor's // main one only if it wasn't granted by another item. if (this.actor.itemTypes.heritage.length === 1 || !this.grantedBy) { - this.actor.heritage = this; + this.actor.heritage = this as HeritagePF2e; } // Add and remove traits as specified @@ -44,9 +45,8 @@ class HeritagePF2e extends ItemPF2e { } } -interface HeritagePF2e extends ItemPF2e { +interface HeritagePF2e extends ItemPF2e { readonly _source: HeritageSource; - readonly parent: CharacterPF2e | null; system: HeritageSystemData; } diff --git a/src/module/item/heritage/sheet.ts b/src/module/item/heritage/sheet.ts index 779d657dc4c..49f4e976965 100644 --- a/src/module/item/heritage/sheet.ts +++ b/src/module/item/heritage/sheet.ts @@ -1,6 +1,6 @@ import { AncestryPF2e, HeritagePF2e, ItemPF2e } from "@item"; import { ItemSheetPF2e } from "@item/sheet/base"; -import { HeritageSheetData } from "@item/sheet/data-types"; +import { ItemSheetDataPF2e } from "@item/sheet/data-types"; import { ErrorPF2e, sluggify } from "@util"; export class HeritageSheetPF2e extends ItemSheetPF2e { @@ -60,3 +60,8 @@ export class HeritageSheetPF2e extends ItemSheetPF2e { await this.item.update({ "system.ancestry": ancestryReference }); } } + +interface HeritageSheetData extends ItemSheetDataPF2e { + ancestry: AncestryPF2e | null; + ancestryRefBroken: boolean; +} diff --git a/src/module/item/index.ts b/src/module/item/index.ts index f6cf3f0dbe6..9d62449f075 100644 --- a/src/module/item/index.ts +++ b/src/module/item/index.ts @@ -3,6 +3,7 @@ export { PhysicalItemPF2e } from "./physical/document"; export { ABCItemPF2e } from "./abc/document"; export { AbstractEffectPF2e } from "./abstract-effect/document"; export { ActionItemPF2e } from "./action/document"; +export { AfflictionPF2e } from "./affliction/document"; export { AncestryPF2e } from "./ancestry/document"; export { ArmorPF2e } from "./armor/document"; export { BackgroundPF2e } from "./background/document"; diff --git a/src/module/item/kit/document.ts b/src/module/item/kit/document.ts index 4ff4fe6a056..0436d27e166 100644 --- a/src/module/item/kit/document.ts +++ b/src/module/item/kit/document.ts @@ -1,4 +1,5 @@ -import { ContainerPF2e, ItemPF2e, PhysicalItemPF2e } from "@item/index"; +import { ActorPF2e } from "@actor"; +import { ItemPF2e, PhysicalItemPF2e } from "@item/index"; import { Price } from "@item/physical/data"; import { CoinsPF2e } from "@item/physical/helpers"; import { DENOMINATIONS } from "@item/physical/values"; @@ -9,7 +10,7 @@ import { KitEntryData, KitSource, KitSystemData } from "./data"; import { Size } from "@module/data"; import { ActorSizePF2e } from "@actor/data/size"; -class KitPF2e extends ItemPF2e { +class KitPF2e extends ItemPF2e { get entries(): KitEntryData[] { return Object.values(this.system.items); } @@ -24,46 +25,49 @@ class KitPF2e extends ItemPF2e { /** Expand a tree of kit entry data into a list of physical items */ override async createGrantedItems( options: { entries?: KitEntryData[]; containerId?: string; size?: Size } = {} - ): Promise { + ): Promise[]> { const size = new ActorSizePF2e({ value: options.size ?? "med", smallIsMedium: true }).value; const entries = options.entries ?? this.entries; const itemUUIDs = entries.map((e): ItemUUID => e.uuid); const items: unknown[] = await UUIDUtils.fromUUIDs(itemUUIDs); if (entries.length !== items.length) throw ErrorPF2e(`Some items from ${this.name} were not found`); - if (!items.every((i): i is ItemPF2e => i instanceof ItemPF2e)) return []; + if (!items.every((i): i is ItemPF2e => i instanceof ItemPF2e && !i.parent)) return []; - return items.reduce(async (promise: PhysicalItemPF2e[] | Promise, item, index) => { - const prepared = await promise; - const clone = item.clone({ _id: randomID(), system: { size } }, { keepId: true }); - const entry = entries[index]; - if (clone instanceof PhysicalItemPF2e) { - clone.updateSource({ - "system.quantity": entry.quantity, - "system.containerId": options.containerId, - }); - } + return items.reduce( + async (promise: PhysicalItemPF2e[] | Promise[]>, item, index) => { + const prepared = await promise; + const clone = item.clone({ _id: randomID(), system: { size } }, { keepId: true }); + const entry = entries[index]; + if (clone.isOfType("physical")) { + clone.updateSource({ + "system.quantity": entry.quantity, + "system.containerId": options.containerId, + }); + } - if (clone instanceof ContainerPF2e && entry.items) { - const contents = await this.createGrantedItems({ - entries: Object.values(entry.items), - containerId: clone.id, - size, - }); - prepared.push(clone, ...contents); - } else if (clone instanceof KitPF2e) { - const inflatedKit = await clone.createGrantedItems({ containerId: options.containerId, size }); - prepared.push(...inflatedKit); - } else if (clone instanceof PhysicalItemPF2e) { - prepared.push(clone); - } + if (clone.isOfType("backpack") && entry.items) { + const contents = await this.createGrantedItems({ + entries: Object.values(entry.items), + containerId: clone.id, + size, + }); + prepared.push(clone, ...contents); + } else if (clone instanceof KitPF2e) { + const inflatedKit = await clone.createGrantedItems({ containerId: options.containerId, size }); + prepared.push(...inflatedKit); + } else if (clone instanceof PhysicalItemPF2e) { + prepared.push(clone); + } - return prepared; - }, []); + return prepared; + }, + [] + ); } protected override async _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { if (!changed.system) return await super._preUpdate(changed, options, user); @@ -82,7 +86,7 @@ class KitPF2e extends ItemPF2e { } } -interface KitPF2e extends ItemPF2e { +interface KitPF2e extends ItemPF2e { readonly _source: KitSource; system: KitSystemData; } diff --git a/src/module/item/lore/index.ts b/src/module/item/lore/index.ts index c5917345800..c23f09cdcd9 100644 --- a/src/module/item/lore/index.ts +++ b/src/module/item/lore/index.ts @@ -1,9 +1,12 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item/base"; import { LoreSource, LoreSystemData } from "./data"; -export class LorePF2e extends ItemPF2e {} +class LorePF2e extends ItemPF2e {} -export interface LorePF2e { +interface LorePF2e extends ItemPF2e { readonly _source: LoreSource; system: LoreSystemData; } + +export { LorePF2e }; diff --git a/src/module/item/melee/document.ts b/src/module/item/melee/document.ts index a3e7fa28685..a18959ceb6b 100644 --- a/src/module/item/melee/document.ts +++ b/src/module/item/melee/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { SIZE_TO_REACH } from "@actor/creature/values"; import { ItemPF2e } from "@item/base"; import { ItemSummaryData } from "@item/data"; @@ -8,7 +9,7 @@ import { ConvertedNPCDamage, WeaponDamagePF2e } from "@system/damage/weapon"; import { tupleHasValue } from "@util"; import { MeleeFlags, MeleeSource, MeleeSystemData, NPCAttackTrait } from "./data"; -class MeleePF2e extends ItemPF2e { +class MeleePF2e extends ItemPF2e { /** Set during data preparation if a linked weapon is found */ category!: WeaponCategory | null; group!: WeaponGroup | null; @@ -96,7 +97,7 @@ class MeleePF2e extends ItemPF2e { } /** The linked inventory weapon, if this melee item was spawned from one */ - get linkedWeapon(): Embedded | null { + get linkedWeapon(): WeaponPF2e | null { const item = this.actor?.items.get(this.flags.pf2e.linkedWeapon ?? ""); return item?.isOfType("weapon") ? item : null; } @@ -198,7 +199,7 @@ class MeleePF2e extends ItemPF2e { } override async getChatData( - this: Embedded, + this: MeleePF2e, htmlOptions: EnrichHTMLOptions = {} ): Promise> { const systemData = this.system; @@ -212,7 +213,7 @@ class MeleePF2e extends ItemPF2e { } } -interface MeleePF2e extends ItemPF2e { +interface MeleePF2e extends ItemPF2e { flags: MeleeFlags; readonly _source: MeleeSource; system: MeleeSystemData; diff --git a/src/module/item/physical/document.ts b/src/module/item/physical/document.ts index 487020798f6..2d692f55e54 100644 --- a/src/module/item/physical/document.ts +++ b/src/module/item/physical/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { type ContainerPF2e, ItemPF2e } from "@item"; import { ItemSummaryData, PhysicalItemSource, TraitChatData } from "@item/data"; import { MystifiedTraits } from "@item/data/values"; @@ -20,9 +21,9 @@ import { PreciousMaterialGrade, PreciousMaterialType } from "./types"; import { getUsageDetails, isEquipped } from "./usage"; import { DENOMINATIONS } from "./values"; -abstract class PhysicalItemPF2e extends ItemPF2e { +abstract class PhysicalItemPF2e extends ItemPF2e { // The cached container of this item, if in a container, or null - private _container: Embedded | null = null; + private _container: ContainerPF2e | null = null; get level(): number { return this.system.level.value; @@ -130,13 +131,10 @@ abstract class PhysicalItemPF2e extends ItemPF2e { } /** Get this item's container, returning null if it is not in a container */ - get container(): Embedded | null { + get container(): ContainerPF2e | null { if (this.system.containerId === null) return (this._container = null); - - const container = this._container ?? this.actor?.items.get(this.system.containerId ?? ""); - if (container?.isOfType("backpack")) this._container = container; - - return this._container; + return (this._container ??= + this.actor?.itemTypes.backpack.find((c) => c.id === this.system.containerId) ?? null); } /** Returns the bulk of this item and all sub-containers */ @@ -405,7 +403,7 @@ abstract class PhysicalItemPF2e extends ItemPF2e { /** Set to unequipped upon acquiring */ protected override async _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { await super._preCreate(data, options, user); @@ -427,7 +425,7 @@ abstract class PhysicalItemPF2e extends ItemPF2e { protected override async _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentUpdateContext, user: UserPF2e ): Promise { // Clamp hit points to between zero and max @@ -480,7 +478,7 @@ abstract class PhysicalItemPF2e extends ItemPF2e { } } -interface PhysicalItemPF2e extends ItemPF2e { +interface PhysicalItemPF2e extends ItemPF2e { readonly _source: PhysicalItemSource; system: PhysicalSystemData; diff --git a/src/module/item/physical/types.ts b/src/module/item/physical/types.ts index 774b463aa16..f780b464a51 100644 --- a/src/module/item/physical/types.ts +++ b/src/module/item/physical/types.ts @@ -1,6 +1,6 @@ import { PHYSICAL_ITEM_TYPES, PRECIOUS_MATERIAL_GRADES, PRECIOUS_MATERIAL_TYPES } from "./values"; -type BaseMaterialType = "cloth" | "glass" | "leather" | "paper" | "rope" | "steel" | "stone" | "wood"; +type BaseMaterialType = "bone" | "cloth" | "glass" | "leather" | "paper" | "rope" | "steel" | "stone" | "wood"; type BaseMaterialThickness = "thin" | "standard" | "structure"; type BaseMaterial = { type: BaseMaterialType; thickness: BaseMaterialThickness }; diff --git a/src/module/item/sheet/data-types.ts b/src/module/item/sheet/data-types.ts index b99dcfd172b..4be4b8129f8 100644 --- a/src/module/item/sheet/data-types.ts +++ b/src/module/item/sheet/data-types.ts @@ -1,9 +1,9 @@ -import { AncestryPF2e, FeatPF2e, HeritagePF2e, ItemPF2e } from "@item"; +import { ItemPF2e } from "@item"; import { Rarity } from "@module/data"; import { RuleElementSource } from "@module/rules"; import { SheetOptions, TraitTagifyEntry } from "@module/sheet/helpers"; -export interface ItemSheetDataPF2e extends ItemSheetData { +interface ItemSheetDataPF2e extends ItemSheetData { /** The item type label that shows at the top right (for example, "Feat" for "Feat 6") */ itemType: string | null; showTraits: boolean; @@ -45,20 +45,4 @@ export interface ItemSheetDataPF2e extends ItemSheetData proficiencies: ConfigPF2e["PF2E"]["proficiencyLevels"]; } -export interface FeatSheetData extends ItemSheetDataPF2e { - featTypes: ConfigPF2e["PF2E"]["featTypes"]; - actionTypes: ConfigPF2e["PF2E"]["actionTypes"]; - actionsNumber: ConfigPF2e["PF2E"]["actionsNumber"]; - frequencies: ConfigPF2e["PF2E"]["frequencies"]; - damageTypes: ConfigPF2e["PF2E"]["damageTypes"] & ConfigPF2e["PF2E"]["healingTypes"]; - categories: ConfigPF2e["PF2E"]["actionCategories"]; - prerequisites: string; - isFeat: boolean; - mandatoryTakeOnce: boolean; - hasLineageTrait: boolean; -} - -export interface HeritageSheetData extends ItemSheetDataPF2e { - ancestry: AncestryPF2e | null; - ancestryRefBroken: boolean; -} +export { ItemSheetDataPF2e }; diff --git a/src/module/item/sheet/rule-elements/base.ts b/src/module/item/sheet/rule-elements/base.ts index 7e440052950..c133ee51057 100644 --- a/src/module/item/sheet/rule-elements/base.ts +++ b/src/module/item/sheet/rule-elements/base.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item/base"; import { RuleElementPF2e, RuleElementSource } from "@module/rules"; @@ -11,7 +12,7 @@ function coerceNumber(value: T): T | number { } interface RuleElementFormOptions { - item: ItemPF2e; + item: ItemPF2e; index: number; rule: TSource; object: TObject | null; @@ -24,7 +25,7 @@ class RuleElementForm< > { template = "systems/pf2e/templates/items/rules/default.hbs"; - readonly item: ItemPF2e; + readonly item: ItemPF2e; readonly index: number; readonly rule: TSource; readonly object: TObject | null; diff --git a/src/module/item/spell/document.ts b/src/module/item/spell/document.ts index 6ab5cf05037..b9925760680 100644 --- a/src/module/item/spell/document.ts +++ b/src/module/item/spell/document.ts @@ -36,24 +36,24 @@ import { applyDamageDiceOverrides, createFormulaAndTagsForPartial, DamageInstanc import { SpellOverlayCollection } from "./overlay"; import { EffectAreaSize, MagicSchool, MagicTradition, SpellComponent, SpellTrait } from "./types"; -interface SpellConstructionContext extends DocumentConstructionContext { +interface SpellConstructionContext extends DocumentConstructionContext { fromConsumable?: boolean; } -class SpellPF2e extends ItemPF2e { +class SpellPF2e extends ItemPF2e { readonly isFromConsumable: boolean; /** The original spell. Only exists if this is a variant */ - original?: SpellPF2e; + original?: SpellPF2e>; /** The overlays that were applied to create this variant */ appliedOverlays?: Map; /** Set if casted with trick magic item. Will be replaced via overriding spellcasting on cast later. */ - trickMagicEntry: TrickMagicItemEntry | null = null; + trickMagicEntry: TrickMagicItemEntry> | null = null; overlays!: SpellOverlayCollection; - constructor(data: PreCreate, context: SpellConstructionContext = {}) { + constructor(data: PreCreate, context: SpellConstructionContext = {}) { super(data, context); this.isFromConsumable = !!context.fromConsumable; } @@ -105,9 +105,11 @@ class SpellPF2e extends ItemPF2e { : new Set(this.system.traditions.value); } - get spellcasting(): BaseSpellcastingEntry | null { + get spellcasting(): BaseSpellcastingEntry> | null { const spellcastingId = this.system.location.value; - return this.actor?.spellcasting.find((entry) => entry.id === spellcastingId) ?? null; + return (this.actor?.spellcasting.find((e) => e.id === spellcastingId) ?? null) as BaseSpellcastingEntry< + NonNullable + > | null; } get isAttack(): boolean { @@ -281,7 +283,7 @@ class SpellPF2e extends ItemPF2e { options, self: { actor: this.actor, - item: this, + item: this as SpellPF2e, statistic: null, token: this.actor.token, modifiers: [], @@ -292,7 +294,8 @@ class SpellPF2e extends ItemPF2e { // Add modifiers and damage die adjustments const modifiers: ModifierPF2e[] = []; const damageDice: DamageDicePF2e[] = []; - if (actor?.isOfType("character", "npc")) { + if (actor.system.abilities) { + const { abilities } = actor.system; const abilityModifiers = Object.entries(this.system.damage.value) .filter(([, d]) => d.applyMod) .map( @@ -302,7 +305,7 @@ class SpellPF2e extends ItemPF2e { slug: `ability-${k}`, // Not a restricted ability modifier in the same way it is for checks or weapon damage type: "untyped", - modifier: actor.abilities[ability].mod, + modifier: abilities[ability].mod, damageType: d.type.value, damageCategory: d.type.subtype ?? null, }) @@ -453,7 +456,7 @@ class SpellPF2e extends ItemPF2e { * This handles heightening as well as alternative cast modes of spells. * If there's nothing to apply, returns null. */ - loadVariant(options: { castLevel?: number; overlayIds?: string[] } = {}): Embedded | null { + loadVariant(options: { castLevel?: number; overlayIds?: string[] } = {}): SpellPF2e> | null { if (this.original) { return this.original.loadVariant(options); } @@ -462,7 +465,7 @@ class SpellPF2e extends ItemPF2e { const heightenEntries = this.getHeightenLayers(castLevel); const overlays = overlayIds?.map((id) => ({ id, data: this.overlays.get(id, { strict: true }) })) ?? []; - const override = (() => { + const overrides = (() => { // If there are no overlays, only return an override if this is a simple heighten if (!heightenEntries.length && !overlays.length) { if (castLevel !== this.level) { @@ -507,11 +510,13 @@ class SpellPF2e extends ItemPF2e { return source; })(); - if (!override) return null; + if (!overrides) return null; const fromConsumable = this.isFromConsumable; - const variant = new SpellPF2e(override, { parent: this.actor, fromConsumable }) as Embedded; - variant.original = this; + const variant = new SpellPF2e(overrides, { parent: this.actor, fromConsumable }) as SpellPF2e< + NonNullable + >; + variant.original = this as SpellPF2e>; variant.appliedOverlays = appliedOverlays; // Retrieve tradition since `#prepareSiblingData` isn't run: variant.system.traits.value = Array.from(new Set([...variant.traits, ...variant.traditions])); @@ -544,7 +549,7 @@ class SpellPF2e extends ItemPF2e { if (!area) throw ErrorPF2e("Attempted to create template with non-area spell"); const areaType = templateConversion[area.type]; - const templateData: DeepPartial = { + const templateData: DeepPartial = { t: areaType, distance: (Number(area.value) / 5) * (canvas.dimensions?.distance ?? 0), fillColor: game.user.color, @@ -598,7 +603,7 @@ class SpellPF2e extends ItemPF2e { this.overlays = new SpellOverlayCollection(this, this.system.overlays); } - override prepareSiblingData(this: Embedded): void { + override prepareSiblingData(this: SpellPF2e): void { this.system.traits.value.push(...this.traditions); if (this.spellcasting?.isInnate) { mergeObject(this.system.location, { uses: { value: 1, max: 1 } }, { overwrite: false }); @@ -701,7 +706,7 @@ class SpellPF2e extends ItemPF2e { } override async getChatData( - this: Embedded, + this: SpellPF2e, htmlOptions: EnrichHTMLOptionsPF2e = {}, rollOptions: { castLevel?: number | string; slotLevel?: number | string } = {} ): Promise> { @@ -843,7 +848,7 @@ class SpellPF2e extends ItemPF2e { } async rollAttack( - this: Embedded, + this: SpellPF2e, event: MouseEvent | JQuery.ClickEvent, attackNumber = 1, context: StatisticRollParameters = {} @@ -861,7 +866,7 @@ class SpellPF2e extends ItemPF2e { } async rollDamage( - this: Embedded, + this: SpellPF2e, event: MouseEvent | JQuery.ClickEvent, mapIncreases?: ZeroToTwo ): Promise | null> { @@ -954,17 +959,21 @@ class SpellPF2e extends ItemPF2e { ); } - override async update(data: DocumentUpdateData, options?: DocumentModificationContext): Promise { + override async update(data: DocumentUpdateData, options: DocumentUpdateContext = {}): Promise { // Redirect the update of override spell variants to the appropriate update method if the spell sheet is currently rendered - if (this.original && this.appliedOverlays!.has("override") && this.sheet.rendered) { - return this.original.overlays.updateOverride(this as Embedded, data, options) as Promise; + if (options.parent && this.original && this.appliedOverlays!.has("override") && this.sheet.rendered) { + return this.original.overlays.updateOverride( + this as SpellPF2e, + data, + options as DocumentUpdateContext + ) as Promise; } return super.update(data, options); } protected override async _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { this._source.system.location.value ||= null; @@ -977,7 +986,7 @@ class SpellPF2e extends ItemPF2e { protected override async _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentUpdateContext, user: UserPF2e ): Promise { await super._preUpdate(changed, options, user); @@ -1009,7 +1018,7 @@ class SpellPF2e extends ItemPF2e { } } -interface SpellPF2e extends ItemPF2e { +interface SpellPF2e extends ItemPF2e { readonly _source: SpellSource; system: SpellSystemData; } diff --git a/src/module/item/spell/overlay.ts b/src/module/item/spell/overlay.ts index 470f363ddeb..2409dccf326 100644 --- a/src/module/item/spell/overlay.ts +++ b/src/module/item/spell/overlay.ts @@ -1,6 +1,7 @@ import { SpellOverlay, SpellOverlayType, SpellSource } from "./data"; import { ErrorPF2e } from "@util"; import { SpellPF2e } from "."; +import { ActorPF2e } from "@actor"; class SpellOverlayCollection extends Collection { constructor(public readonly spell: SpellPF2e, entries?: Record) { @@ -8,8 +9,8 @@ class SpellOverlayCollection extends Collection { } /** Returns all variants based on override overlays */ - get overrideVariants(): Embedded[] { - return [...this.entries()].reduce((result: Embedded[], [overlayId, data]) => { + get overrideVariants(): SpellPF2e[] { + return [...this.entries()].reduce((result: SpellPF2e[], [overlayId, data]) => { if (data.overlayType === "override") { const spell = this.spell.loadVariant({ overlayIds: [overlayId] }); if (spell) return [...result, spell]; @@ -48,10 +49,10 @@ class SpellOverlayCollection extends Collection { } async updateOverride( - variantSpell: Embedded, + variantSpell: SpellPF2e, data: Partial, - options?: DocumentModificationContext - ): Promise> { + options?: DocumentModificationContext + ): Promise> { // Perform local data update of spell variant data variantSpell.updateSource(data, options); diff --git a/src/module/item/spell/sheet.ts b/src/module/item/spell/sheet.ts index cb008339d8e..491ba84e775 100644 --- a/src/module/item/spell/sheet.ts +++ b/src/module/item/spell/sheet.ts @@ -6,6 +6,7 @@ import { ErrorPF2e, fontAwesomeIcon, getActionGlyph, objectHasKey, pick, tagify, import { OneToTen } from "@module/data"; import { DamageCategoryUnique } from "@system/damage/types"; import { DAMAGE_CATEGORIES_UNIQUE } from "@system/damage/values"; +import { ActorPF2e } from "@actor"; /** Set of properties that are legal for the purposes of spell overrides */ const spellOverridable: Partial> = { @@ -300,7 +301,7 @@ export class SpellSheetPF2e extends ItemSheetPF2e { // Handle closing of override spell variant sheets if (this.item.original && this.item.appliedOverlays!.has("override") && !this.rendered) { - await this.item.original.overlays.updateOverride(this.item as Embedded, formData); + await this.item.original.overlays.updateOverride(this.item as SpellPF2e, formData); return; } diff --git a/src/module/item/spellcasting-entry/collection.ts b/src/module/item/spellcasting-entry/collection.ts index 3e12adccf47..aa09f1651a3 100644 --- a/src/module/item/spellcasting-entry/collection.ts +++ b/src/module/item/spellcasting-entry/collection.ts @@ -6,12 +6,14 @@ import { SlotKey } from "./data"; import { RitualSpellcasting } from "./rituals"; import { ActiveSpell, BaseSpellcastingEntry, SpellcastingSlotLevel, SpellPrepEntry } from "./types"; -class SpellCollection extends Collection> { - readonly entry: BaseSpellcastingEntry; +class SpellCollection> extends Collection< + SpellPF2e +> { + readonly entry: TEntry; - readonly actor: ActorPF2e; + readonly actor: TActor; - constructor(entry: BaseSpellcastingEntry) { + constructor(entry: TEntry) { if (!entry.actor) throw ErrorPF2e("a spell collection must have an associated actor"); super(); @@ -29,7 +31,9 @@ class SpellCollection extends Collection> { return Math.min(10, Math.max(highestSpell, actorSpellLevel)); } - #assertEntryIsDocument(entry: BaseSpellcastingEntry): asserts entry is SpellcastingEntryPF2e { + #assertEntryIsDocument( + entry: BaseSpellcastingEntry + ): asserts entry is SpellcastingEntryPF2e { if (!(entry instanceof ItemPF2e)) { throw ErrorPF2e("`this#entry` is not a `SpellcastingEntryPF2e`"); } @@ -39,8 +43,8 @@ class SpellCollection extends Collection> { * Adds a spell to this spellcasting entry, either moving it from another one if its the same actor, * or creating a new spell if its not. If given a level, it will heighten to that level if it can be. */ - async addSpell(spell: SpellPF2e, options: { slotLevel?: number } = {}): Promise { - const actor = this.actor; + async addSpell(spell: SpellPF2e, options: { slotLevel?: number } = {}): Promise | null> { + const { actor } = this; if (!actor.isOfType("creature")) { throw ErrorPF2e("Spellcasting entries can only exist on creatures"); } @@ -84,7 +88,10 @@ class SpellCollection extends Collection> { canHeighten && heightenLevel >= spell.baseLevel ? { "system.location.heightenedLevel": heightenLevel } : {}; if (spell.actor === actor) { - return spell.update({ "system.location.value": this.id, ...heightenedUpdate }); + return spell.update({ + "system.location.value": this.id, + ...heightenedUpdate, + }) as Promise | null>; } else { const source = spell.clone({ "system.location.value": this.id, ...heightenedUpdate }).toObject(); const created = (await actor.createEmbeddedDocuments("Item", [source])).shift(); @@ -94,7 +101,7 @@ class SpellCollection extends Collection> { } /** Saves the prepared spell slot data to the spellcasting entry */ - async prepareSpell(spell: SpellPF2e, slotLevel: number, spellSlot: number): Promise { + async prepareSpell(spell: SpellPF2e, slotLevel: number, spellSlot: number): Promise { this.#assertEntryIsDocument(this.entry); if (spell.baseLevel > slotLevel && !(slotLevel === 0 && spell.isCantrip)) { @@ -134,7 +141,7 @@ class SpellCollection extends Collection> { } /** Removes the spell slot and updates the spellcasting entry */ - unprepareSpell(slotLevel: number, spellSlot: number): Promise { + unprepareSpell(slotLevel: number, spellSlot: number): Promise { this.#assertEntryIsDocument(this.entry); if (CONFIG.debug.hooks === true) { @@ -155,7 +162,7 @@ class SpellCollection extends Collection> { } /** Sets the expended state of a spell slot and updates the spellcasting entry */ - setSlotExpendedState(slotLevel: number, spellSlot: number, isExpended: boolean): Promise { + setSlotExpendedState(slotLevel: number, spellSlot: number, isExpended: boolean): Promise { this.#assertEntryIsDocument(this.entry); const key = `system.slots.slot${slotLevel}.prepared.${spellSlot}.expended`; @@ -233,7 +240,7 @@ class SpellCollection extends Collection> { if (leveled.length) { const active = await Promise.all(leveled.map(async (spell) => ({ spell }))); results.push({ - label: actor.isOfType("character") ? "PF2E.Focus.Spells" : "PF2E.Focus.Pool", + label: actor.type === "character" ? "PF2E.Focus.Spells" : "PF2E.Focus.Pool", level: Math.max(1, Math.ceil(actor.level / 2)) as OneToTen, isCantrip: false, uses: actor.system.resources.focus ?? { value: 0, max: 0 }, @@ -333,7 +340,7 @@ class SpellCollection extends Collection> { return { levels, spellPrepList: null }; } - protected getSpellPrepList(spells: Embedded[]): Record | null { + protected getSpellPrepList(spells: SpellPF2e[]): Record | null { if (!this.entry.isPrepared) return {}; const spellPrepList: Record = {}; diff --git a/src/module/item/spellcasting-entry/document.ts b/src/module/item/spellcasting-entry/document.ts index 965d42180f6..1fb17a1397d 100644 --- a/src/module/item/spellcasting-entry/document.ts +++ b/src/module/item/spellcasting-entry/document.ts @@ -1,4 +1,4 @@ -import { CharacterPF2e, NPCPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e, NPCPF2e } from "@actor"; import { AbilityString } from "@actor/types"; import { ItemPF2e, PhysicalItemPF2e, SpellPF2e } from "@item"; import { MagicTradition } from "@item/spell/types"; @@ -16,8 +16,11 @@ import { SpellcastingSheetData, } from "./types"; -class SpellcastingEntryPF2e extends ItemPF2e implements SpellcastingEntry { - spells!: SpellCollection | null; +class SpellcastingEntryPF2e + extends ItemPF2e + implements SpellcastingEntry +{ + spells!: SpellCollection, this> | null; /** Spellcasting attack and dc data created during actor preparation */ statistic!: Statistic; @@ -97,11 +100,11 @@ class SpellcastingEntryPF2e extends ItemPF2e implements SpellcastingEntry { } } - override prepareSiblingData(): void { + override prepareSiblingData(this: SpellcastingEntryPF2e): void { if (!this.actor || this.system.prepared.value === "items") { this.spells = null; } else { - this.spells = new SpellCollection(this as Embedded); + this.spells = new SpellCollection(this); const spells = this.actor.itemTypes.spell.filter((i) => i.system.location.value === this.id); for (const spell of spells) { this.spells.set(spell.id, spell); @@ -111,7 +114,7 @@ class SpellcastingEntryPF2e extends ItemPF2e implements SpellcastingEntry { } } - override prepareActorData(this: Embedded): void { + override prepareActorData(this: SpellcastingEntryPF2e): void { const actor = this.actor; // Upgrade the actor proficiency using the internal ones @@ -126,7 +129,7 @@ class SpellcastingEntryPF2e extends ItemPF2e implements SpellcastingEntry { } /** All spells associated with this spellcasting entry on the actor that should also be deleted */ - override getLinkedItems(): Embedded[] { + override getLinkedItems(): SpellPF2e[] { return this.actor?.itemTypes.spell.filter((i) => i.system.location.value === this.id) ?? []; } @@ -156,7 +159,7 @@ class SpellcastingEntryPF2e extends ItemPF2e implements SpellcastingEntry { } /** Casts the given spell as if it was part of this spellcasting entry */ - async cast(spell: Embedded, options: SpellcastingEntryPF2eCastOptions = {}): Promise { + async cast(spell: SpellPF2e, options: SpellcastingEntryPF2eCastOptions = {}): Promise { const consume = options.consume ?? true; const message = options.message ?? true; const slotLevel = options.level ?? spell.level; @@ -167,7 +170,7 @@ class SpellcastingEntryPF2e extends ItemPF2e implements SpellcastingEntry { } } - async consume(spell: SpellPF2e, level: number, slot?: number): Promise { + async consume(spell: SpellPF2e, level: number, slot?: number): Promise { const actor = this.actor; if (!(actor instanceof CharacterPF2e || actor instanceof NPCPF2e)) { throw ErrorPF2e("Spellcasting entries require an actor"); @@ -244,26 +247,25 @@ class SpellcastingEntryPF2e extends ItemPF2e implements SpellcastingEntry { * Adds a spell to this spellcasting entry, either moving it from another one if its the same actor, * or creating a new spell if its not. */ - async addSpell(spell: SpellPF2e, options?: { slotLevel?: number }): Promise { + async addSpell( + spell: SpellPF2e, + options?: { slotLevel?: number } + ): Promise> | null> { return this.spells?.addSpell(spell, options) ?? null; } /** Saves the prepared spell slot data to the spellcasting entry */ - async prepareSpell(spell: SpellPF2e, slotLevel: number, spellSlot: number): Promise { + async prepareSpell(spell: SpellPF2e, slotLevel: number, spellSlot: number): Promise { return this.spells?.prepareSpell(spell, slotLevel, spellSlot) ?? null; } /** Removes the spell slot and updates the spellcasting entry */ - async unprepareSpell(spellLevel: number, slotLevel: number): Promise { + async unprepareSpell(spellLevel: number, slotLevel: number): Promise { return this.spells?.unprepareSpell(spellLevel, slotLevel) ?? null; } /** Sets the expended state of a spell slot and updates the spellcasting entry */ - async setSlotExpendedState( - slotLevel: number, - spellSlot: number, - isExpended: boolean - ): Promise { + async setSlotExpendedState(slotLevel: number, spellSlot: number, isExpended: boolean): Promise { return this.spells?.setSlotExpendedState(slotLevel, spellSlot, isExpended) ?? null; } @@ -305,7 +307,7 @@ class SpellcastingEntryPF2e extends ItemPF2e implements SpellcastingEntry { protected override async _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, user: UserPF2e ): Promise { // Clamp slot updates @@ -341,7 +343,7 @@ class SpellcastingEntryPF2e extends ItemPF2e implements SpellcastingEntry { } } -interface SpellcastingEntryPF2e extends ItemPF2e { +interface SpellcastingEntryPF2e extends ItemPF2e { readonly _source: SpellcastingEntrySource; system: SpellcastingEntrySystemData; } diff --git a/src/module/item/spellcasting-entry/rituals.ts b/src/module/item/spellcasting-entry/rituals.ts index 12db45a1890..70fc3a9df0b 100644 --- a/src/module/item/spellcasting-entry/rituals.ts +++ b/src/module/item/spellcasting-entry/rituals.ts @@ -5,12 +5,12 @@ import { SpellCollection } from "./collection"; import { BaseSpellcastingEntry, CastOptions, SpellcastingSheetData } from "./types"; /** An in-memory spellcasting entry for rituals */ -export class RitualSpellcasting implements BaseSpellcastingEntry { - actor: ActorPF2e; +export class RitualSpellcasting implements BaseSpellcastingEntry { + actor: TActor; - spells: SpellCollection; + spells: SpellCollection; - constructor(actor: ActorPF2e, rituals: Embedded[]) { + constructor(actor: TActor, rituals: SpellPF2e[]) { this.actor = actor; this.spells = new SpellCollection(this); for (const ritual of rituals) { diff --git a/src/module/item/spellcasting-entry/trick.ts b/src/module/item/spellcasting-entry/trick.ts index 6025f9071cf..bbcb44cb467 100644 --- a/src/module/item/spellcasting-entry/trick.ts +++ b/src/module/item/spellcasting-entry/trick.ts @@ -1,9 +1,10 @@ -import { CharacterPF2e } from "@actor"; +import { ActorPF2e } from "@actor"; import { AbilityString } from "@actor/types"; import { SpellPF2e } from "@item"; import { extractModifiers } from "@module/rules/helpers"; import { Statistic } from "@system/statistic"; import { CastOptions, SpellcastingEntry, SpellcastingSheetData } from "./types"; +import { ErrorPF2e } from "@util"; const TRICK_MAGIC_SKILLS = ["arcana", "nature", "occultism", "religion"] as const; type TrickMagicItemSkill = (typeof TRICK_MAGIC_SKILLS)[number]; @@ -23,7 +24,7 @@ const traditionSkills = { } as const; /** A pseudo spellcasting entry used to trick magic item for a single skill */ -class TrickMagicItemEntry implements SpellcastingEntry { +class TrickMagicItemEntry implements SpellcastingEntry { readonly id = `trick-${this.skill}`; statistic: Statistic; @@ -32,7 +33,12 @@ class TrickMagicItemEntry implements SpellcastingEntry { tradition = TrickMagicTradition[this.skill]; - constructor(public actor: CharacterPF2e, public skill: TrickMagicItemSkill) { + constructor(public actor: TActor, public skill: TrickMagicItemSkill) { + if (!actor.isOfType("character")) { + throw ErrorPF2e("Trick magic entries may only be constructed with PCs"); + } + this.actor = actor as TActor; + const { abilities } = actor; const { ability } = (["int", "wis", "cha"] as const) .map((ability) => { diff --git a/src/module/item/spellcasting-entry/types.ts b/src/module/item/spellcasting-entry/types.ts index a8645710dc3..7f69e4b9db5 100644 --- a/src/module/item/spellcasting-entry/types.ts +++ b/src/module/item/spellcasting-entry/types.ts @@ -8,10 +8,10 @@ import { Statistic, StatisticChatData } from "@system/statistic"; import { SpellCollection } from "./collection"; import { SpellcastingEntrySystemData } from "./data"; -interface BaseSpellcastingEntry { +interface BaseSpellcastingEntry { id: string; name: string; - actor: ActorPF2e | null; + actor: TActor; sort: number; category: SpellcastingCategory; ability?: AbilityString; @@ -23,7 +23,7 @@ interface BaseSpellcastingEntry { isSpontaneous: boolean; statistic?: Statistic | null; tradition: MagicTradition | null; - spells: SpellCollection | null; + spells: SpellCollection, this> | null; system?: SpellcastingEntrySystemData; getSheetData(): Promise; @@ -33,7 +33,7 @@ interface BaseSpellcastingEntry { cast(spell: SpellPF2e, options: CastOptions): Promise; } -interface SpellcastingEntry extends BaseSpellcastingEntry { +interface SpellcastingEntry extends BaseSpellcastingEntry { ability: AbilityString; statistic: Statistic; } @@ -57,7 +57,7 @@ type OptionalProperties = "isFlexible" | "isFocusPool" | "isInnate" | "isPrepare /** Spell list render data for a `BaseSpellcastingEntry` */ interface SpellcastingSheetData - extends Omit { + extends Omit, "statistic" | OptionalProperties | UnusedProperties> { statistic: StatisticChatData | null; hasCollection: boolean; flexibleAvailable?: { value: number; max: number } | null; @@ -91,12 +91,12 @@ interface SpellcastingSlotLevel { } interface SpellPrepEntry { - spell: Embedded; + spell: SpellPF2e; signature?: boolean; } interface ActiveSpell { - spell: Embedded; + spell: SpellPF2e; /** The level at which a spell is cast (if prepared or automatically heighted) */ castLevel?: number; expended?: boolean; diff --git a/src/module/item/treasure/document.ts b/src/module/item/treasure/document.ts index 02e52aac721..2cbeec61236 100644 --- a/src/module/item/treasure/document.ts +++ b/src/module/item/treasure/document.ts @@ -1,9 +1,10 @@ +import { ActorPF2e } from "@actor"; import { ItemSummaryData } from "@item/data"; import { PhysicalItemPF2e } from "@item/physical"; import { DENOMINATIONS } from "@item/physical/values"; import { TreasureSource, TreasureSystemData } from "./data"; -class TreasurePF2e extends PhysicalItemPF2e { +class TreasurePF2e extends PhysicalItemPF2e { get isCoinage(): boolean { return this.system.stackGroup === "coins"; } @@ -23,7 +24,7 @@ class TreasurePF2e extends PhysicalItemPF2e { } override async getChatData( - this: Embedded, + this: TreasurePF2e, htmlOptions: EnrichHTMLOptions = {} ): Promise { const systemData = this.system; @@ -33,7 +34,7 @@ class TreasurePF2e extends PhysicalItemPF2e { } } -interface TreasurePF2e extends PhysicalItemPF2e { +interface TreasurePF2e extends PhysicalItemPF2e { readonly _source: TreasureSource; system: TreasureSystemData; } diff --git a/src/module/item/types.ts b/src/module/item/types.ts new file mode 100644 index 00000000000..9b8feae2920 --- /dev/null +++ b/src/module/item/types.ts @@ -0,0 +1,29 @@ +import { ActorPF2e } from "@actor"; +import * as ItemInstance from "@item"; + +interface ItemInstances { + action: ItemInstance.ActionItemPF2e; + affliction: ItemInstance.AfflictionPF2e; + ancestry: ItemInstance.AncestryPF2e; + armor: ItemInstance.ArmorPF2e; + background: ItemInstance.BackgroundPF2e; + backpack: ItemInstance.ContainerPF2e; + book: ItemInstance.BookPF2e; + class: ItemInstance.ClassPF2e; + condition: ItemInstance.ConditionPF2e; + consumable: ItemInstance.ConsumablePF2e; + deity: ItemInstance.DeityPF2e; + effect: ItemInstance.EffectPF2e; + equipment: ItemInstance.EquipmentPF2e; + feat: ItemInstance.FeatPF2e; + heritage: ItemInstance.HeritagePF2e; + kit: ItemInstance.KitPF2e; + lore: ItemInstance.LorePF2e; + melee: ItemInstance.MeleePF2e; + spell: ItemInstance.SpellPF2e; + spellcastingEntry: ItemInstance.SpellcastingEntryPF2e; + treasure: ItemInstance.TreasurePF2e; + weapon: ItemInstance.WeaponPF2e; +} + +export { ItemInstances }; diff --git a/src/module/item/weapon/document.ts b/src/module/item/weapon/document.ts index eb36174197e..3381d0a2df9 100644 --- a/src/module/item/weapon/document.ts +++ b/src/module/item/weapon/document.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { AutomaticBonusProgression as ABP } from "@actor/character/automatic-bonus-progression"; import { ActorSizePF2e } from "@actor/data/size"; import { ConsumablePF2e, MeleePF2e, PhysicalItemPF2e } from "@item"; @@ -36,7 +37,7 @@ import { } from "./types"; import { CROSSBOW_WEAPONS, MANDATORY_RANGED_GROUPS, THROWN_RANGES } from "./values"; -class WeaponPF2e extends PhysicalItemPF2e { +class WeaponPF2e extends PhysicalItemPF2e { /** Given this weapon is an alternative usage, whether it is melee or thrown */ altUsageType: "melee" | "thrown" | null = null; @@ -51,7 +52,7 @@ class WeaponPF2e extends PhysicalItemPF2e { return super.isEquipped || (this.handsHeld === 1 && traits.value.some((t) => /^jousting-d\d{1,2}$/.test(t))); } - override isStackableWith(item: PhysicalItemPF2e): boolean { + override isStackableWith(item: PhysicalItemPF2e): boolean { if (this.category === "unarmed" || !item.isOfType("weapon") || item.category === "unarmed") { return false; } @@ -134,7 +135,7 @@ class WeaponPF2e extends PhysicalItemPF2e { return this.isRanged && ![null, "-"].includes(this.reload); } - get ammo(): Embedded | null { + get ammo(): ConsumablePF2e> | null { const ammo = this.actor?.items.get(this.system.selectedAmmoId ?? ""); return ammo instanceof ConsumablePF2e && ammo.quantity > 0 ? ammo : null; } @@ -436,7 +437,7 @@ class WeaponPF2e extends PhysicalItemPF2e { } override async getChatData( - this: Embedded, + this: WeaponPF2e, htmlOptions: EnrichHTMLOptions = {} ): Promise { const traits = this.traitChatData(CONFIG.PF2E.weaponTraits); @@ -533,7 +534,7 @@ class WeaponPF2e extends PhysicalItemPF2e { * @param [options.recurse=true] Whether to get the alternative usages of alternative usages */ getAltUsages(options?: { recurse?: boolean }): this[]; - getAltUsages({ recurse = true } = {}): WeaponPF2e[] { + getAltUsages({ recurse = true } = {}): WeaponPF2e[] { const meleeUsage = this.toMeleeUsage(); return [ @@ -605,7 +606,7 @@ class WeaponPF2e extends PhysicalItemPF2e { } /** Generate a melee item from this weapon for use by NPCs */ - toNPCAttacks(this: Embedded): Embedded[] { + toNPCAttacks(this: WeaponPF2e): MeleePF2e[] { const { actor } = this; if (!actor.isOfType("npc")) throw ErrorPF2e("Melee items can only be generated for NPCs"); @@ -745,7 +746,7 @@ class WeaponPF2e extends PhysicalItemPF2e { flags: { pf2e: { linkedWeapon: this.id } }, }; - const attack = new MeleePF2e(source, { parent: this.actor }) as Embedded; + const attack = new MeleePF2e(source, { parent: this.actor }); // Melee items retrieve these during `prepareSiblingData`, but if the attack is from a Strike rule element, // there will be no inventory weapon from which to pull the data. attack.category = this.category; @@ -761,7 +762,7 @@ class WeaponPF2e extends PhysicalItemPF2e { protected override _preUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentUpdateContext, user: UserPF2e ): Promise { const traits = changed.system?.traits ?? {}; @@ -773,7 +774,7 @@ class WeaponPF2e extends PhysicalItemPF2e { } /** Remove links to this weapon from NPC attacks */ - protected override _onDelete(options: DocumentModificationContext, userId: string): void { + protected override _onDelete(options: DocumentModificationContext, userId: string): void { super._onDelete(options, userId); if (game.user.id === userId) { @@ -786,7 +787,7 @@ class WeaponPF2e extends PhysicalItemPF2e { } } -interface WeaponPF2e extends PhysicalItemPF2e { +interface WeaponPF2e extends PhysicalItemPF2e { flags: WeaponFlags; readonly _source: WeaponSource; system: WeaponSystemData; diff --git a/src/module/journal-entry/sheet.ts b/src/module/journal-entry/sheet.ts index 1eb6e20e5ce..7095a1fd8e2 100644 --- a/src/module/journal-entry/sheet.ts +++ b/src/module/journal-entry/sheet.ts @@ -1,6 +1,6 @@ import type * as TinyMCE from "tinymce"; -class JournalSheetPF2e extends JournalSheet { +class JournalSheetPF2e extends JournalSheet { static get theme(): string | null { return null; } @@ -16,7 +16,9 @@ class JournalSheetPF2e extend } } -class JournalTextTinyMCESheetPF2e extends JournalTextTinyMCESheet { +class JournalTextTinyMCESheetPF2e< + TDocument extends JournalEntryPage +> extends JournalTextTinyMCESheet { override async activateEditor( name: string, options: Partial = {}, diff --git a/src/module/macro.ts b/src/module/macro.ts index 929d9eb2139..b6c1dc820e5 100644 --- a/src/module/macro.ts +++ b/src/module/macro.ts @@ -1,3 +1,5 @@ +import { ChatMessagePF2e } from "./chat-message"; + export class MacroPF2e extends Macro { /** Raise permission requirement of world macro visibility to observer */ override get visible(): boolean { @@ -5,9 +7,12 @@ export class MacroPF2e extends Macro { } /** Allow unbound variables to be shadowed in script's evaluation scope */ - protected override _executeScript({ actor, token }: { actor?: Actor; token?: Token | null } = {}): void { + protected override _executeScript({ + actor, + token, + }: { actor?: Actor | null>; token?: Token | null } = {}): void { // Add variables to the evaluation scope - const speaker = ChatMessage.implementation.getSpeaker(); + const speaker = ChatMessagePF2e.getSpeaker(); const character = game.user.character; actor ??= game.actors.get(speaker.actor ?? ""); token ??= canvas.ready ? canvas.tokens.get(speaker.token ?? "") : null; diff --git a/src/module/migration/base.ts b/src/module/migration/base.ts index 2102621be8c..072570b8561 100644 --- a/src/module/migration/base.ts +++ b/src/module/migration/base.ts @@ -62,20 +62,20 @@ interface MigrationBase { * Update the macro to the latest schema version. * @param source Macro data to update. This should be a `MacroData` from the previous version. */ - updateMacro?(source: foundry.data.MacroSource): Promise; + updateMacro?(source: foundry.documents.MacroSource): Promise; /** * Update the rollable table to the latest schema version. * @param source Rolltable data to update. This should be a `RollTableData` from the previous version. */ - updateTable?(source: foundry.data.RollTableSource): Promise; + updateTable?(source: foundry.documents.RollTableSource): Promise; /** * Update the token to the latest schema version. * @param tokenData Token data to update. This should be a `TokenData` from the previous version. */ updateToken?( - tokenData: foundry.data.TokenSource, + tokenData: foundry.documents.TokenSource, actor: Readonly, scene: Readonly ): Promise; diff --git a/src/module/migration/migrations/601-migrate-effect-compendia.ts b/src/module/migration/migrations/601-migrate-effect-compendia.ts index 39dd10dbc3c..74037760b95 100644 --- a/src/module/migration/migrations/601-migrate-effect-compendia.ts +++ b/src/module/migration/migrations/601-migrate-effect-compendia.ts @@ -213,8 +213,8 @@ export class Migration601SplitEffectCompendia extends MigrationBase { } override async migrate(): Promise { - game.macros.forEach((macro) => { - macro.data.command = macro.data.command.replace( + for (const macro of game.macros) { + macro._source.command = macro._source.command.replace( /(Compendium\.pf2e\.)(spell-effects)(\.)([a-zA-Z0-9]{16})/g, (_full, first, _replace, dot, itemId): string => { const packName = objectHasKey(Migration601SplitEffectCompendia.effectLocations, itemId) @@ -223,6 +223,6 @@ export class Migration601SplitEffectCompendia extends MigrationBase { return first + packName + dot + itemId; } ); - }); + } } } diff --git a/src/module/migration/migrations/602-update-diehard-feat.ts b/src/module/migration/migrations/602-update-diehard-feat.ts index 307652056af..a907349672f 100644 --- a/src/module/migration/migrations/602-update-diehard-feat.ts +++ b/src/module/migration/migrations/602-update-diehard-feat.ts @@ -6,7 +6,7 @@ export class Migration602UpdateDiehardFeat extends MigrationBase { static override version = 0.602; override requiresFlush = true; - private diehardPromise: Promise; + private diehardPromise: Promise; constructor() { super(); diff --git a/src/module/migration/migrations/611-update-toughness-mountains-stoutness.ts b/src/module/migration/migrations/611-update-toughness-mountains-stoutness.ts index f29a21c36b1..40a9c2f472a 100644 --- a/src/module/migration/migrations/611-update-toughness-mountains-stoutness.ts +++ b/src/module/migration/migrations/611-update-toughness-mountains-stoutness.ts @@ -9,11 +9,11 @@ export class Migration611UpdateToughnessMountainsStoutness extends MigrationBase override requiresFlush = true; private featSlugs = ["mountains-stoutness", "mountain-s-stoutness", "toughness"]; - private featsPromise: Promise; + private featsPromise: Promise[]>; constructor() { super(); - this.featsPromise = game.packs.get>("pf2e.feats-srd")!.getDocuments(); + this.featsPromise = game.packs.get>>("pf2e.feats-srd")!.getDocuments(); } override async updateActor(actorData: ActorSourcePF2e) { diff --git a/src/module/migration/migrations/620-rename-to-webp.ts b/src/module/migration/migrations/620-rename-to-webp.ts index 6077653be85..5dabd7ff1e3 100644 --- a/src/module/migration/migrations/620-rename-to-webp.ts +++ b/src/module/migration/migrations/620-rename-to-webp.ts @@ -70,18 +70,18 @@ export class Migration620RenameToWebp extends MigrationBase { } } - override async updateMacro(macroData: foundry.data.MacroSource): Promise { + override async updateMacro(macroData: foundry.documents.MacroSource): Promise { macroData.img = this.renameToWebP(macroData.img); } - override async updateTable(tableData: foundry.data.RollTableSource): Promise { + override async updateTable(tableData: foundry.documents.RollTableSource): Promise { tableData.img = this.renameToWebP(tableData.img); for (const result of tableData.results) { result.img = this.renameToWebP(result.img); } } - override async updateToken(tokenData: foundry.data.TokenSource): Promise { + override async updateToken(tokenData: foundry.documents.TokenSource): Promise { tokenData.texture.src = this.renameToWebP(tokenData.texture.src); tokenData.effects = tokenData.effects.filter((texture) => !this.regexp.test(texture)); } diff --git a/src/module/migration/migrations/624-removed-token-effect-icon-flags.ts b/src/module/migration/migrations/624-removed-token-effect-icon-flags.ts index 7c1c020b67b..403704004bf 100644 --- a/src/module/migration/migrations/624-removed-token-effect-icon-flags.ts +++ b/src/module/migration/migrations/624-removed-token-effect-icon-flags.ts @@ -15,7 +15,7 @@ export class Migration624RemoveTokenEffectIconFlags extends MigrationBase { } } - override async updateToken(tokenData: foundry.data.TokenSource): Promise { + override async updateToken(tokenData: foundry.documents.TokenSource): Promise { // remove deprecated rule element token effects const flags = (tokenData.actorData.flags ?? {}) as TokenEffectsFlag; if (flags.pf2e?.token?.effects) { diff --git a/src/module/migration/migrations/645-token-image-size.ts b/src/module/migration/migrations/645-token-image-size.ts index 720a80705fd..3081aa5a32b 100644 --- a/src/module/migration/migrations/645-token-image-size.ts +++ b/src/module/migration/migrations/645-token-image-size.ts @@ -43,7 +43,7 @@ export class Migration645TokenImageSize extends MigrationBase { } override async updateToken( - tokenSource: foundry.data.TokenSource, + tokenSource: foundry.documents.TokenSource, actor: Readonly ): Promise { tokenSource.texture.src = this.imageOverrides.get(actor?.id ?? "") ?? tokenSource.texture.src; diff --git a/src/module/migration/migrations/653-aes-to-res.ts b/src/module/migration/migrations/653-aes-to-res.ts index a0adadb3d68..527068a24c3 100644 --- a/src/module/migration/migrations/653-aes-to-res.ts +++ b/src/module/migration/migrations/653-aes-to-res.ts @@ -18,11 +18,11 @@ export class Migration653AEstoREs extends MigrationBase { "system.attributes.classDC.rank", ]); - private isRemovableAE(effect: foundry.data.ActiveEffectSource): boolean { + private isRemovableAE(effect: foundry.documents.ActiveEffectSource): boolean { return effect.changes.every(this.isRemoveableChange); } - private isRemoveableChange(change: foundry.data.EffectChangeSource) { + private isRemoveableChange(change: foundry.documents.EffectChangeSource) { return ( (change.mode !== 0 && Number.isInteger(Number(change.value))) || (change.mode === 5 && !change.value.startsWith("{")) diff --git a/src/module/migration/migrations/662-link-to-actor-size-defaults.ts b/src/module/migration/migrations/662-link-to-actor-size-defaults.ts index a163f35897a..72e81a569c8 100644 --- a/src/module/migration/migrations/662-link-to-actor-size-defaults.ts +++ b/src/module/migration/migrations/662-link-to-actor-size-defaults.ts @@ -13,7 +13,7 @@ export class Migration662LinkToActorSizeDefaults extends MigrationBase { actorSource.prototypeToken.flags.pf2e.linkToActorSize ??= linkToActorSize; } - override async updateToken(tokenSource: foundry.data.TokenSource, actor: ActorPF2e): Promise { + override async updateToken(tokenSource: foundry.documents.TokenSource, actor: ActorPF2e): Promise { const linkToActorSize = !["hazard", "loot"].includes(actor.type); tokenSource.flags.pf2e ??= { linkToActorSize }; tokenSource.flags.pf2e.linkToActorSize ??= linkToActorSize; diff --git a/src/module/migration/migrations/676-replace-items-with-re-like-aes.ts b/src/module/migration/migrations/676-replace-items-with-re-like-aes.ts index c4492d349dd..04eb5f9398a 100644 --- a/src/module/migration/migrations/676-replace-items-with-re-like-aes.ts +++ b/src/module/migration/migrations/676-replace-items-with-re-like-aes.ts @@ -58,5 +58,5 @@ interface ReplaceItemArgs { items: ItemSourcePF2e[]; type: string; slug: string; - replacement: ClientDocument | ClientDocument2 | null; + replacement: ClientDocument | null; } diff --git a/src/module/migration/migrations/692-crafting-entry-feat-replacement.ts b/src/module/migration/migrations/692-crafting-entry-feat-replacement.ts index 4624ddcd377..52264d9cfc2 100644 --- a/src/module/migration/migrations/692-crafting-entry-feat-replacement.ts +++ b/src/module/migration/migrations/692-crafting-entry-feat-replacement.ts @@ -9,10 +9,7 @@ export class Migration692CraftingEntryFeatReplacement extends MigrationBase { static override version = 0.692; override requiresFlush = true; - private slugToPromise = new Map< - string, - Promise | ClientDocument2 | null> - >([ + private slugToPromise = new Map>([ ["advanced-alchemy", fromUuid("Compendium.pf2e.classfeatures.Pe0zmIqyTBc2Td0I")], ["field-discovery-bomber", fromUuid("Compendium.pf2e.classfeatures.8QAFgy9U8PxEa7Dw")], ["field-discovery-chirurgeon", fromUuid("Compendium.pf2e.classfeatures.qC0Iz6SlG2i9gv6g")], @@ -71,5 +68,5 @@ export class Migration692CraftingEntryFeatReplacement extends MigrationBase { interface ReplaceItemArgs { items: ItemSourcePF2e[]; current: ItemSourcePF2e; - replacement: ClientDocument | ClientDocument2 | null; + replacement: ClientDocument | null; } diff --git a/src/module/migration/migrations/723-cumulative-item-bonuses.ts b/src/module/migration/migrations/723-cumulative-item-bonuses.ts index 8ccd5a1dc56..798d231bfc2 100644 --- a/src/module/migration/migrations/723-cumulative-item-bonuses.ts +++ b/src/module/migration/migrations/723-cumulative-item-bonuses.ts @@ -70,7 +70,7 @@ export class Migration723CumulativeItemBonuses extends MigrationBase { } /** Replace the retired toggle macro with a simple hotbar-drop effect macro */ - override async updateMacro(source: foundry.data.MacroSource): Promise { + override async updateMacro(source: foundry.documents.MacroSource): Promise { if (source.type === "script" && source.command.includes("Stance: Mountain Stance")) { source.command = String.raw`const actors = canvas.tokens.controlled.flatMap((token) => token.actor ?? []); if (actors.length === 0 && game.user.character) actors.push(game.user.character); diff --git a/src/module/migration/runner/base.ts b/src/module/migration/runner/base.ts index 5f523a0f3c7..daf7982f2c4 100644 --- a/src/module/migration/runner/base.ts +++ b/src/module/migration/runner/base.ts @@ -3,9 +3,10 @@ import { ItemSourcePF2e } from "@item/data"; import { DocumentSchemaRecord } from "@module/data"; import { MigrationBase } from "@module/migration/base"; import { TokenDocumentPF2e } from "@module/scene/token-document"; +import { ScenePF2e } from "@scene"; import { DateTime } from "luxon"; -interface CollectionDiff { +interface CollectionDiff { inserted: T[]; deleted: string[]; updated: T[]; @@ -28,13 +29,13 @@ export class MigrationRunnerBase { return currentVersion < (this.constructor as typeof MigrationRunnerBase).LATEST_SCHEMA_VERSION; } - diffCollection(orig: T[], updated: T[]): CollectionDiff; + diffCollection(orig: T[], updated: T[]): CollectionDiff; diffCollection(orig: T[], updated: T[]): CollectionDiff; - diffCollection( + diffCollection( orig: T[], updated: T[] ): CollectionDiff; - diffCollection( + diffCollection( orig: TSource[], updated: TSource[] ): CollectionDiff { @@ -133,9 +134,9 @@ export class MigrationRunnerBase { } async getUpdatedTable( - tableSource: foundry.data.RollTableSource, + tableSource: foundry.documents.RollTableSource, migrations: MigrationBase[] - ): Promise { + ): Promise { const current = deepClone(tableSource); for (const migration of migrations) { @@ -150,9 +151,9 @@ export class MigrationRunnerBase { } async getUpdatedMacro( - macroSource: foundry.data.MacroSource, + macroSource: foundry.documents.MacroSource, migrations: MigrationBase[] - ): Promise { + ): Promise { const current = deepClone(macroSource); for (const migration of migrations) { @@ -183,7 +184,10 @@ export class MigrationRunnerBase { return clone; } - async getUpdatedToken(token: TokenDocumentPF2e, migrations: MigrationBase[]): Promise { + async getUpdatedToken( + token: TokenDocumentPF2e, + migrations: MigrationBase[] + ): Promise { const current = token.toObject(); for (const migration of migrations) { await migration.updateToken?.(current, token.actor, token.scene); diff --git a/src/module/migration/runner/index.ts b/src/module/migration/runner/index.ts index cfb7e5d44fd..b8d58df1afb 100644 --- a/src/module/migration/runner/index.ts +++ b/src/module/migration/runner/index.ts @@ -7,6 +7,7 @@ import type { UserPF2e } from "@module/user"; import { TokenDocumentPF2e } from "@module/scene/token-document"; import { ItemSourcePF2e } from "@item/data"; import { ActorSourcePF2e } from "@actor/data"; +import { ScenePF2e } from "@scene"; export class MigrationRunner extends MigrationRunnerBase { override needsMigration(): boolean { @@ -45,11 +46,11 @@ export class MigrationRunner extends MigrationRunnerBase { } /** Migrate actor or item documents in batches of 50 */ - private async migrateDocuments( + async #migrateDocuments | ItemPF2e>( collection: WorldCollection | CompendiumCollection, migrations: MigrationBase[] ): Promise { - const DocumentClass = collection.documentClass as unknown as typeof ClientDocument; + const DocumentClass = collection.documentClass; const pack = "metadata" in collection ? collection.metadata.id : null; const updateGroup: TDocument["_source"][] = []; // Have familiars go last so that their data migration and re-preparation happen after their master's @@ -65,8 +66,8 @@ export class MigrationRunner extends MigrationRunnerBase { } const updated = "items" in document - ? await this.migrateActor(migrations, document, { pack }) - : await this.migrateItem(migrations, document, { pack }); + ? await this.#migrateActor(migrations, document, { pack }) + : await this.#migrateItem(migrations, document, { pack }); if (updated) updateGroup.push(updated); } if (updateGroup.length > 0) { @@ -78,7 +79,7 @@ export class MigrationRunner extends MigrationRunnerBase { } } - private async migrateItem( + async #migrateItem( migrations: MigrationBase[], item: ItemPF2e, options: { pack?: string | null } = {} @@ -113,7 +114,7 @@ export class MigrationRunner extends MigrationRunnerBase { return updatedItem; } - private async migrateActor( + async #migrateActor( migrations: MigrationBase[], actor: ActorPF2e, options: { pack?: string | null } = {} @@ -191,7 +192,7 @@ export class MigrationRunner extends MigrationRunnerBase { return updatedActor; } - private async migrateWorldJournalEntry(journalEntry: JournalEntry, migrations: MigrationBase[]): Promise { + async #migrateWorldJournalEntry(journalEntry: JournalEntry, migrations: MigrationBase[]): Promise { if (!migrations.some((migration) => !!migration.updateJournalEntry)) return; try { @@ -205,7 +206,7 @@ export class MigrationRunner extends MigrationRunnerBase { } } - private async migrateWorldMacro(macro: MacroPF2e, migrations: MigrationBase[]): Promise { + async #migrateWorldMacro(macro: MacroPF2e, migrations: MigrationBase[]): Promise { if (!migrations.some((migration) => !!migration.updateMacro)) return; try { @@ -219,7 +220,7 @@ export class MigrationRunner extends MigrationRunnerBase { } } - private async migrateWorldTable(table: RollTable, migrations: MigrationBase[]): Promise { + async #migrateWorldTable(table: RollTable, migrations: MigrationBase[]): Promise { if (!migrations.some((migration) => !!migration.updateTable)) return; try { @@ -233,10 +234,10 @@ export class MigrationRunner extends MigrationRunnerBase { } } - private async migrateSceneToken( - token: TokenDocumentPF2e, + async #migrateSceneToken( + token: TokenDocumentPF2e, migrations: MigrationBase[] - ): Promise { + ): Promise { if (!migrations.some((migration) => !!migration.updateToken)) return token.toObject(); try { @@ -257,7 +258,7 @@ export class MigrationRunner extends MigrationRunnerBase { } } - private async migrateUser(user: UserPF2e, migrations: MigrationBase[]): Promise { + async #migrateUser(user: UserPF2e, migrations: MigrationBase[]): Promise { if (!migrations.some((migration) => !!migration.updateUser)) return; try { @@ -272,7 +273,7 @@ export class MigrationRunner extends MigrationRunnerBase { } } - async runCompendiumMigration(compendium: CompendiumCollection) { + async runCompendiumMigration | ItemPF2e>(compendium: CompendiumCollection) { ui.notifications.info(game.i18n.format("PF2E.Migrations.Starting", { version: game.system.version }), { permanent: true, }); @@ -284,7 +285,7 @@ export class MigrationRunner extends MigrationRunnerBase { ); const migrations = this.migrations.filter((migration) => migration.version > lowestSchemaVersion); - await this.migrateDocuments(compendium, migrations); + await this.#migrateDocuments(compendium, migrations); ui.notifications.info(game.i18n.format("PF2E.Migrations.Finished", { version: game.system.version }), { permanent: true, @@ -295,29 +296,29 @@ export class MigrationRunner extends MigrationRunnerBase { if (migrations.length === 0) return; // Migrate World Actors - await this.migrateDocuments(game.actors as WorldCollection, migrations); + await this.#migrateDocuments(game.actors as WorldCollection>, migrations); // Migrate World Items - await this.migrateDocuments(game.items, migrations); + await this.#migrateDocuments(game.items, migrations); // Migrate world journal entries for (const entry of game.journal) { - await this.migrateWorldJournalEntry(entry, migrations); + await this.#migrateWorldJournalEntry(entry, migrations); } const promises: Promise[] = []; // Migrate World Macros for (const macro of game.macros) { - promises.push(this.migrateWorldMacro(macro, migrations)); + promises.push(this.#migrateWorldMacro(macro, migrations)); } // Migrate World RollTables for (const table of game.tables) { - promises.push(this.migrateWorldTable(table, migrations)); + promises.push(this.#migrateWorldTable(table, migrations)); } for (const user of game.users) { - promises.push(this.migrateUser(user, migrations)); + promises.push(this.#migrateUser(user, migrations)); } // call the free-form migration function. can really do anything @@ -336,7 +337,7 @@ export class MigrationRunner extends MigrationRunnerBase { const { actor } = token; if (!actor) continue; - const wasSuccessful = !!(await this.migrateSceneToken(token, migrations)); + const wasSuccessful = !!(await this.#migrateSceneToken(token, migrations)); if (!wasSuccessful) continue; // Only migrate if the synthetic actor has replaced migratable data @@ -345,7 +346,7 @@ export class MigrationRunner extends MigrationRunnerBase { Object.keys(token._source.actorData).some((k) => ["items", "system"].includes(k)); if (actor.isToken && hasMigratableData) { - const updated = await this.migrateActor(migrations, actor); + const updated = await this.#migrateActor(migrations, actor); if (updated) { try { await actor.update(updated); diff --git a/src/module/rules/index.ts b/src/module/rules/index.ts index 8b79d785b98..533cd42f5a0 100644 --- a/src/module/rules/index.ts +++ b/src/module/rules/index.ts @@ -47,6 +47,7 @@ import { TokenImageRuleElement } from "./rule-element/token-image"; import { TokenLightRuleElement } from "./rule-element/token-light"; import { TokenNameRuleElement } from "./rule-element/token-name"; import { WeaponPotencyRuleElement } from "./rule-element/weapon-potency"; +import { ActorPF2e } from "@actor"; export { RuleElementSynthetics } from "./synthetics"; /** @@ -102,7 +103,7 @@ class RuleElements { return { ...this.builtin, ...this.custom }; } - static fromOwnedItem(item: Embedded, options?: RuleElementOptions): RuleElementPF2e[] { + static fromOwnedItem(item: ItemPF2e, options?: RuleElementOptions): RuleElementPF2e[] { const rules: RuleElementPF2e[] = []; for (const [sourceIndex, source] of item.system.rules.entries()) { if (typeof source.key !== "string") { @@ -139,7 +140,7 @@ class RuleElements { type RuleElementConstructor = { schema: LaxSchemaField } & (new ( data: RuleElementSource, - item: Embedded, + item: ItemPF2e, options?: RuleElementOptions ) => RuleElementPF2e); diff --git a/src/module/rules/rule-element/actor-traits.ts b/src/module/rules/rule-element/actor-traits.ts index 555458645c5..b51ddd106dd 100644 --- a/src/module/rules/rule-element/actor-traits.ts +++ b/src/module/rules/rule-element/actor-traits.ts @@ -1,12 +1,13 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item"; -import { RuleElementPF2e, RuleElementSource, RuleElementOptions } from "./"; +import { RuleElementOptions, RuleElementPF2e, RuleElementSource } from "./"; class ActorTraitsRuleElement extends RuleElementPF2e { add: string[] = []; remove: string[] = []; - constructor(data: ActorTraitsSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: ActorTraitsSource, item: ItemPF2e, options?: RuleElementOptions) { data.add ??= []; data.remove ??= []; diff --git a/src/module/rules/rule-element/adjust-degree-of-success.ts b/src/module/rules/rule-element/adjust-degree-of-success.ts index d06e809f500..272f52d36f2 100644 --- a/src/module/rules/rule-element/adjust-degree-of-success.ts +++ b/src/module/rules/rule-element/adjust-degree-of-success.ts @@ -1,4 +1,4 @@ -import { CharacterPF2e, NPCPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e, NPCPF2e } from "@actor"; import { ItemPF2e } from "@item"; import { DegreeAdjustmentAmount, @@ -15,7 +15,7 @@ import { RuleElementData, RuleElementOptions, RuleElementPF2e, RuleElementSource class AdjustDegreeOfSuccessRuleElement extends RuleElementPF2e { selector: string; - constructor(data: AdjustDegreeOfSuccessSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: AdjustDegreeOfSuccessSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); if (typeof data.selector === "string") { @@ -71,7 +71,7 @@ class AdjustDegreeOfSuccessRuleElement extends RuleElementPF2e { } } -interface AdjustDegreeOfSuccessRuleElement { +interface AdjustDegreeOfSuccessRuleElement extends RuleElementPF2e { data: RuleElementData & { adjustment?: DegreeAdjustmentsRuleRecord }; get actor(): CharacterPF2e | NPCPF2e; diff --git a/src/module/rules/rule-element/adjust-modifier.ts b/src/module/rules/rule-element/adjust-modifier.ts index 0b6d6a984d9..f3546812330 100644 --- a/src/module/rules/rule-element/adjust-modifier.ts +++ b/src/module/rules/rule-element/adjust-modifier.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ModifierAdjustment } from "@actor/modifiers"; import { ItemPF2e } from "@item"; import { DamageType } from "@system/damage/types"; @@ -21,7 +22,7 @@ class AdjustModifierRuleElement extends AELikeRuleElement /** The number of times this adjustment has been applied */ applications = 0; - constructor(data: AdjustModifierSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: AdjustModifierSource, item: ItemPF2e, options?: RuleElementOptions) { data.path = "ignore"; // Maybe this shouldn't subclass AELikeRuleElement if (data.suppress) { diff --git a/src/module/rules/rule-element/adjust-strike.ts b/src/module/rules/rule-element/adjust-strike.ts index 6776c3427d8..60650893a95 100644 --- a/src/module/rules/rule-element/adjust-strike.ts +++ b/src/module/rules/rule-element/adjust-strike.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ActorType } from "@actor/data"; import { ItemPF2e, MeleePF2e, WeaponPF2e } from "@item"; import { ActionTrait } from "@item/action/data"; @@ -15,7 +16,7 @@ const { fields } = foundry.data; class AdjustStrikeRuleElement extends AELikeRuleElement { protected static override validActorTypes: ActorType[] = ["character", "familiar", "npc"]; - constructor(data: AdjustStrikeSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: AdjustStrikeSource, item: ItemPF2e, options?: RuleElementOptions) { super({ ...data, path: "ignore", phase: "beforeDerived", priority: 110 }, item, options); } diff --git a/src/module/rules/rule-element/ae-like.ts b/src/module/rules/rule-element/ae-like.ts index 7603480f375..783a1095974 100644 --- a/src/module/rules/rule-element/ae-like.ts +++ b/src/module/rules/rule-element/ae-like.ts @@ -1,14 +1,15 @@ +import { ActorPF2e } from "@actor"; import { SKILL_EXPANDED, SKILL_LONG_FORMS } from "@actor/values"; import { FeatPF2e, ItemPF2e } from "@item"; import { isObject, objectHasKey } from "@util"; import { ModelPropsFromSchema, StringField } from "types/foundry/common/data/fields.mjs"; import { - RuleElementPF2e, - RuleElementSource, RuleElementData, RuleElementOptions, - RuleValue, + RuleElementPF2e, RuleElementSchema, + RuleElementSource, + RuleValue, } from "./"; const { fields } = foundry.data; @@ -18,7 +19,7 @@ const { fields } = foundry.data; * @category RuleElement */ class AELikeRuleElement extends RuleElementPF2e { - constructor(data: AELikeSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: AELikeSource, item: ItemPF2e, options?: RuleElementOptions) { const hasExplicitPriority = typeof data.priority === "number"; super(data, item, options); diff --git a/src/module/rules/rule-element/aura.ts b/src/module/rules/rule-element/aura.ts index 93073a5b0d0..4c28e7e5049 100644 --- a/src/module/rules/rule-element/aura.ts +++ b/src/module/rules/rule-element/aura.ts @@ -5,6 +5,7 @@ import { PredicatePF2e } from "@system/predication"; import { isObject, sluggify } from "@util"; import { RuleElementOptions, RuleElementPF2e, RuleElementSource } from "./"; import { UUIDUtils } from "@util/uuid-utils"; +import { ActorPF2e } from "@actor"; /** A Pathfinder 2e aura, capable of transmitting effects and with a visual representation on the canvas */ export class AuraRuleElement extends RuleElementPF2e { @@ -25,7 +26,7 @@ export class AuraRuleElement extends RuleElementPF2e { */ colors: AuraColors | null; - constructor(source: AuraRuleElementSource, item: Embedded, options?: RuleElementOptions) { + constructor(source: AuraRuleElementSource, item: ItemPF2e, options?: RuleElementOptions) { source.effects ??= []; source.traits ??= []; diff --git a/src/module/rules/rule-element/base-speed.ts b/src/module/rules/rule-element/base-speed.ts index b2a0038a25f..831af5df9a7 100644 --- a/src/module/rules/rule-element/base-speed.ts +++ b/src/module/rules/rule-element/base-speed.ts @@ -1,4 +1,4 @@ -import { CreaturePF2e } from "@actor"; +import { ActorPF2e, CreaturePF2e } from "@actor"; import { MovementType } from "@actor/creature/data"; import { ActorType } from "@actor/data"; import { MOVEMENT_TYPES } from "@actor/values"; @@ -17,7 +17,7 @@ class BaseSpeedRuleElement extends RuleElementPF2e { private value: number | string | BracketedValue = 0; - constructor(data: BaseSpeedSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: BaseSpeedSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); this.selector = String(data.selector) diff --git a/src/module/rules/rule-element/base.ts b/src/module/rules/rule-element/base.ts index 65c9b35b0ea..6f2b8eae3e3 100644 --- a/src/module/rules/rule-element/base.ts +++ b/src/module/rules/rule-element/base.ts @@ -3,12 +3,12 @@ import { ActorType } from "@actor/data"; import { DiceModifierPF2e, ModifierPF2e } from "@actor/modifiers"; import { ItemPF2e, PhysicalItemPF2e, WeaponPF2e } from "@item"; import { ItemSourcePF2e } from "@item/data"; -import { LaxSchemaField, PredicateField, SlugField } from "@system/schema-data-fields"; import { TokenDocumentPF2e } from "@scene"; import { CheckRoll } from "@system/check"; +import { LaxSchemaField, PredicateField, SlugField } from "@system/schema-data-fields"; import { isObject, tupleHasValue } from "@util"; -import { BracketedValue, RuleElementData, RuleElementSchema, RuleElementSource, RuleValue } from "./data"; import { DataModelValidationOptions } from "types/foundry/common/abstract/module.mjs"; +import { BracketedValue, RuleElementData, RuleElementSchema, RuleElementSource, RuleValue } from "./data"; const { DataModel } = foundry.abstract; const { fields } = foundry.data; @@ -33,7 +33,7 @@ abstract class RuleElementPF2e, options: RuleElementOptions = {}) { + constructor(source: RuleElementSource, public item: ItemPF2e, options: RuleElementOptions = {}) { source.label ??= item.name; super(source, { strict: false }); @@ -417,16 +417,16 @@ namespace RuleElementPF2e { /** All items pending creation in a `ItemPF2e.createDocuments` call */ pendingItems: PreCreate[]; /** The context object from the `ItemPF2e.createDocuments` call */ - context: DocumentModificationContext; + context: DocumentModificationContext; /** Whether this preCreate run is from a pre-update reevaluation */ reevaluation?: boolean; } export interface PreDeleteParams { /** All items pending deletion in a `ItemPF2e.deleteDocuments` call */ - pendingItems: Embedded[]; + pendingItems: ItemPF2e[]; /** The context object from the `ItemPF2e.deleteDocuments` call */ - context: DocumentModificationContext; + context: DocumentModificationContext; } export interface AfterRollParams { diff --git a/src/module/rules/rule-element/battle-form/rule-element.ts b/src/module/rules/rule-element/battle-form/rule-element.ts index 8c29a4dd449..768d9d52fc3 100644 --- a/src/module/rules/rule-element/battle-form/rule-element.ts +++ b/src/module/rules/rule-element/battle-form/rule-element.ts @@ -7,7 +7,7 @@ import { WeaknessRuleElement } from "../iwr/weakness"; import { SenseRuleElement } from "../sense"; import { StrikeRuleElement } from "../strike"; import { TempHPRuleElement } from "../temp-hp"; -import { CharacterPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e } from "@actor"; import { SENSE_TYPES } from "@actor/creature/sense"; import { ActorType } from "@actor/data"; import { MOVEMENT_TYPES, SKILL_ABBREVIATIONS, SKILL_DICTIONARY } from "@actor/values"; @@ -30,7 +30,7 @@ export class BattleFormRuleElement extends RuleElementPF2e { protected static override validActorTypes: ActorType[] = ["character"]; - constructor(data: BattleFormSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: BattleFormSource, item: ItemPF2e, options?: RuleElementOptions) { data.value ??= {}; data.overrides ??= {}; super(data, item, options); diff --git a/src/module/rules/rule-element/choice-set/rule-element.ts b/src/module/rules/rule-element/choice-set/rule-element.ts index 01a96f1d268..397a91b70e5 100644 --- a/src/module/rules/rule-element/choice-set/rule-element.ts +++ b/src/module/rules/rule-element/choice-set/rule-element.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { StrikeData } from "@actor/data/base"; import { FeatPF2e, ItemPF2e } from "@item"; import { ItemType } from "@item/data"; @@ -34,7 +35,7 @@ class ChoiceSetRuleElement extends RuleElementPF2e { /** The user's selection from among the options in `choices`, or otherwise `null` */ selection: string | number | object | null; - constructor(data: ChoiceSetSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: ChoiceSetSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); this.flag = this.#setDefaultFlag(this.data); @@ -318,7 +319,7 @@ class ChoiceSetRuleElement extends RuleElementPF2e { type: itemType, }; const items = (await pack?.getDocuments(query)) ?? []; - if (!items.every((i): i is ItemPF2e => i instanceof ItemPF2e)) { + if (!items.every((i): i is ItemPF2e => i instanceof ItemPF2e)) { return []; } diff --git a/src/module/rules/rule-element/crafting/entry.ts b/src/module/rules/rule-element/crafting/entry.ts index b605c70cff0..b25f9852a21 100644 --- a/src/module/rules/rule-element/crafting/entry.ts +++ b/src/module/rules/rule-element/crafting/entry.ts @@ -1,5 +1,5 @@ import { RuleElementPF2e, RuleElementData, RuleElementSource, RuleElementOptions } from ".."; -import { CharacterPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e } from "@actor"; import { ActorType } from "@actor/data"; import { ItemPF2e } from "@item"; import { sluggify } from "@util"; @@ -13,7 +13,7 @@ class CraftingEntryRuleElement extends RuleElementPF2e { private selector: string; - constructor(data: CraftingEntryRuleSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: CraftingEntryRuleSource, item: ItemPF2e, options?: RuleElementOptions) { super({ maxItemLevel: 1, priority: 19, ...data }, item, options); if (data.selector && typeof data.selector === "string") { diff --git a/src/module/rules/rule-element/crafting/formula.ts b/src/module/rules/rule-element/crafting/formula.ts index f7e5484aa67..8fbd6df6a2d 100644 --- a/src/module/rules/rule-element/crafting/formula.ts +++ b/src/module/rules/rule-element/crafting/formula.ts @@ -1,6 +1,6 @@ import { RuleElementPF2e, RuleElementData, RuleElementSource, RuleElementOptions } from ".."; import { ActorType } from "@actor/data"; -import { CharacterPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e } from "@actor"; import { ItemPF2e } from "@item"; /** @@ -9,7 +9,7 @@ import { ItemPF2e } from "@item"; class CraftingFormulaRuleElement extends RuleElementPF2e { protected static override validActorTypes: ActorType[] = ["character"]; - constructor(data: CraftingFormulaSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: CraftingFormulaSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); if (!(typeof data.uuid === "string" && /^(?:Compendium|Item)\..*[a-z0-9]{16}$/i.test(data.uuid))) { diff --git a/src/module/rules/rule-element/creature-size.ts b/src/module/rules/rule-element/creature-size.ts index eb649bf8c40..99712f65367 100644 --- a/src/module/rules/rule-element/creature-size.ts +++ b/src/module/rules/rule-element/creature-size.ts @@ -1,4 +1,4 @@ -import { CreaturePF2e } from "@actor"; +import { ActorPF2e, CreaturePF2e } from "@actor"; import { SIZE_TO_REACH } from "@actor/creature/values"; import { ActorType } from "@actor/data"; import { ActorSizePF2e } from "@actor/data/size"; @@ -21,7 +21,7 @@ class CreatureSizeRuleElement extends RuleElementPF2e { resizeEquipment: boolean; - constructor(data: CreatureSizeSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: CreatureSizeSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); this.resizeEquipment = !!data.resizeEquipment; diff --git a/src/module/rules/rule-element/damage-dice.ts b/src/module/rules/rule-element/damage-dice.ts index d07ca1fcb21..d01ccaa4d6c 100644 --- a/src/module/rules/rule-element/damage-dice.ts +++ b/src/module/rules/rule-element/damage-dice.ts @@ -1,4 +1,4 @@ -import { CharacterPF2e, NPCPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e, NPCPF2e } from "@actor"; import { DamageDiceOverride, DamageDicePF2e, DeferredValueParams } from "@actor/modifiers"; import { ItemPF2e } from "@item"; import { CriticalInclusion, DamageDieSize } from "@system/damage/types"; @@ -26,7 +26,7 @@ class DamageDiceRuleElement extends RuleElementPF2e { override: DamageDiceOverride | null; - constructor(data: DamageDiceSource, item: Embedded) { + constructor(data: DamageDiceSource, item: ItemPF2e) { super(data, item); if (typeof data.selector === "string" && data.selector.length > 0) { diff --git a/src/module/rules/rule-element/fast-healing.ts b/src/module/rules/rule-element/fast-healing.ts index a874eb7b8ee..99577a7281c 100644 --- a/src/module/rules/rule-element/fast-healing.ts +++ b/src/module/rules/rule-element/fast-healing.ts @@ -1,10 +1,11 @@ +import { ActorPF2e } from "@actor"; import { ActorType } from "@actor/data"; import { ItemPF2e } from "@item"; import { ChatMessagePF2e } from "@module/chat-message"; import { DamageRoll } from "@system/damage/roll"; import { LocalizePF2e } from "@system/localize"; -import { tupleHasValue, objectHasKey, localizeList } from "@util"; -import { RuleElementPF2e, RuleElementSource, RuleElementOptions, RuleElementData } from "."; +import { localizeList, objectHasKey, tupleHasValue } from "@util"; +import { RuleElementData, RuleElementOptions, RuleElementPF2e, RuleElementSource } from "."; /** * Rule element to implement fast healing and regeneration. @@ -20,7 +21,7 @@ class FastHealingRuleElement extends RuleElementPF2e implements FastHealingData #details?: string; - constructor(data: FastHealingSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: FastHealingSource, item: ItemPF2e, options?: RuleElementOptions) { data.type ??= "fast-healing"; super(data, item, options); diff --git a/src/module/rules/rule-element/fixed-proficiency.ts b/src/module/rules/rule-element/fixed-proficiency.ts index 120f6cce74e..c6e07a029a2 100644 --- a/src/module/rules/rule-element/fixed-proficiency.ts +++ b/src/module/rules/rule-element/fixed-proficiency.ts @@ -1,4 +1,4 @@ -import { CharacterPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e } from "@actor"; import { ActorType } from "@actor/data"; import { ModifierPF2e, MODIFIER_TYPE, StatisticModifier } from "@actor/modifiers"; import { AbilityString } from "@actor/types"; @@ -21,7 +21,7 @@ class FixedProficiencyRuleElement extends RuleElementPF2e { private ability: AbilityString | null; - constructor(data: FixedProficiencySource, item: Embedded, options?: RuleElementOptions) { + constructor(data: FixedProficiencySource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); if (typeof data.selector === "string") { diff --git a/src/module/rules/rule-element/flat-modifier.ts b/src/module/rules/rule-element/flat-modifier.ts index 4ed83a51c45..3032491da91 100644 --- a/src/module/rules/rule-element/flat-modifier.ts +++ b/src/module/rules/rule-element/flat-modifier.ts @@ -1,4 +1,5 @@ -import { DeferredValueParams, ModifierPF2e, ModifierType, MODIFIER_TYPES } from "@actor/modifiers"; +import { ActorPF2e } from "@actor"; +import { DeferredValueParams, MODIFIER_TYPES, ModifierPF2e, ModifierType } from "@actor/modifiers"; import { AbilityString } from "@actor/types"; import { ABILITY_ABBREVIATIONS } from "@actor/values"; import { ItemPF2e } from "@item"; @@ -21,7 +22,7 @@ const { fields } = foundry.data; * @category RuleElement */ class FlatModifierRuleElement extends RuleElementPF2e { - constructor(source: FlatModifierSource, item: Embedded, options?: RuleElementOptions) { + constructor(source: FlatModifierSource, item: ItemPF2e, options?: RuleElementOptions) { if (!item.isOfType("physical") && source.type !== "item") { source.fromEquipment = false; } diff --git a/src/module/rules/rule-element/grant-item/helpers.ts b/src/module/rules/rule-element/grant-item/helpers.ts index f70b8152787..3302a2728fc 100644 --- a/src/module/rules/rule-element/grant-item/helpers.ts +++ b/src/module/rules/rule-element/grant-item/helpers.ts @@ -1,7 +1,8 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item"; /** Check an item prior to its deletion for GrantItem on-delete actions */ -async function processGrantDeletions(item: Embedded, pendingItems: Embedded[]): Promise { +async function processGrantDeletions(item: ItemPF2e, pendingItems: ItemPF2e[]): Promise { const { actor } = item; const granter = actor.items.get(item.flags.pf2e.grantedBy?.id ?? ""); diff --git a/src/module/rules/rule-element/grant-item/rule-element.ts b/src/module/rules/rule-element/grant-item/rule-element.ts index d06e7582bfa..0c05974f546 100644 --- a/src/module/rules/rule-element/grant-item/rule-element.ts +++ b/src/module/rules/rule-element/grant-item/rule-element.ts @@ -12,6 +12,7 @@ import { ChoiceSetSource } from "../choice-set/data"; import { ChoiceSetRuleElement } from "../choice-set/rule-element"; import { ItemAlterationField, WithItemAlterations } from "../mixins"; import { GrantItemSchema } from "./schema"; +import { ActorPF2e } from "@actor"; const { fields } = foundry.data; @@ -30,7 +31,7 @@ class GrantItemRuleElement extends RuleElementPF2e { /** Actions taken when either the parent or child item are deleted */ onDeleteActions: Partial | null; - constructor(data: GrantItemSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: GrantItemSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); if (this.reevaluateOnUpdate) { @@ -152,7 +153,7 @@ class GrantItemRuleElement extends RuleElementPF2e { grantedSource.flags = mergeObject(grantedSource.flags, { core: { sourceId: uuid } }); // Create a temporary owned item and run its actor-data preparation and early-stage rule-element callbacks - const tempGranted = new ItemProxyPF2e(deepClone(grantedSource), { parent: this.actor }) as Embedded; + const tempGranted = new ItemProxyPF2e(deepClone(grantedSource), { parent: this.actor }); tempGranted.prepareActorData?.(); for (const rule of tempGranted.prepareRuleElements({ suppressWarnings: true })) { rule.onApplyActiveEffects?.(); @@ -235,7 +236,7 @@ class GrantItemRuleElement extends RuleElementPF2e { return null; } - #applyChoiceSelections(grantedItem: Embedded): void { + #applyChoiceSelections(grantedItem: ItemPF2e): void { const source = grantedItem._source; for (const [flag, selection] of Object.entries(this.preselectChoices ?? {})) { const rule = grantedItem.rules.find( @@ -250,7 +251,7 @@ class GrantItemRuleElement extends RuleElementPF2e { } /** Set flags on granting and grantee items to indicate relationship between the two */ - #setGrantFlags(granter: PreCreate, grantee: ItemSourcePF2e | ItemPF2e): void { + #setGrantFlags(granter: PreCreate, grantee: ItemSourcePF2e | ItemPF2e): void { const flags = mergeObject(granter.flags ?? {}, { pf2e: { itemGrants: {} } }); if (!this.flag) throw ErrorPF2e("Unexpected failure looking up RE flag key"); flags.pf2e.itemGrants[this.flag] = { @@ -283,9 +284,9 @@ class GrantItemRuleElement extends RuleElementPF2e { /** Run the preCreate callbacks of REs from the granted item */ async #runGrantedItemPreCreates( originalArgs: Omit, - grantedItem: Embedded, + grantedItem: ItemPF2e, grantedSource: ItemSourcePF2e, - context: DocumentModificationContext + context: DocumentModificationContext ): Promise { // Create a temporary embedded version of the item to run its pre-create REs for (const rule of grantedItem.rules) { @@ -300,7 +301,7 @@ class GrantItemRuleElement extends RuleElementPF2e { } /** If this item is being tracked, set an actor flag and add its item roll options to the `all` domain */ - #trackItem(grantedItem: Embedded | null): void { + #trackItem(grantedItem: ItemPF2e | null): void { if (!(this.track && this.flag && this.grantedId && grantedItem instanceof PhysicalItemPF2e)) { return; } diff --git a/src/module/rules/rule-element/iwr/base.ts b/src/module/rules/rule-element/iwr/base.ts index 9b27f3c0817..8f7a751d439 100644 --- a/src/module/rules/rule-element/iwr/base.ts +++ b/src/module/rules/rule-element/iwr/base.ts @@ -1,13 +1,14 @@ -import { RuleElementPF2e, RuleElementSource, RuleElementOptions, RuleElementSchema } from "../"; -import { ItemPF2e } from "@item"; +import { ActorPF2e } from "@actor"; import { ImmunityData, ResistanceData, WeaknessData } from "@actor/data/iwr"; +import { ItemPF2e } from "@item"; import { ArrayField, BooleanField, ModelPropsFromSchema, StringField } from "types/foundry/common/data/fields.mjs"; +import { RuleElementOptions, RuleElementPF2e, RuleElementSchema, RuleElementSource } from "../"; const { fields } = foundry.data; /** @category RuleElement */ abstract class IWRRuleElement extends RuleElementPF2e { - constructor(data: IWRRuleElementSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: IWRRuleElementSource, item: ItemPF2e, options?: RuleElementOptions) { if (typeof data.type === "string") { data.type = [data.type]; } diff --git a/src/module/rules/rule-element/lose-hit-points.ts b/src/module/rules/rule-element/lose-hit-points.ts index bceace3b6a0..2d787b5aa10 100644 --- a/src/module/rules/rule-element/lose-hit-points.ts +++ b/src/module/rules/rule-element/lose-hit-points.ts @@ -1,4 +1,4 @@ -import { CreaturePF2e } from "@actor"; +import { ActorPF2e, CreaturePF2e } from "@actor"; import { ActorType } from "@actor/data"; import { ItemPF2e } from "@item"; import { ItemSourcePF2e } from "@item/data"; @@ -15,7 +15,7 @@ export class LoseHitPointsRuleElement extends RuleElementPF2e { */ private reevaluateOnUpdate: boolean; - constructor(data: LoseHitPointsSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: LoseHitPointsSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); const valueIsValid = typeof data.value === "number" || typeof data.value === "string"; diff --git a/src/module/rules/rule-element/mark-token/prompt.ts b/src/module/rules/rule-element/mark-token/prompt.ts index 6d46fb4e613..3acf165543b 100644 --- a/src/module/rules/rule-element/mark-token/prompt.ts +++ b/src/module/rules/rule-element/mark-token/prompt.ts @@ -8,16 +8,16 @@ class MarkTargetPrompt { requirements: TargetRequirements | null; - #target?: TokenDocumentPF2e | null; + #target?: Maybe; - #resolve?: (value: TokenDocumentPF2e | null) => void; + #resolve?: (value: Maybe) => void; constructor(params: PromptParameters) { this.prompt = params.prompt ?? "PF2E.UI.RuleElements.MarkTarget.TargetToken"; this.requirements = params.requirements; } - async resolveTarget(): Promise { + async resolveTarget(): Promise> { game.user.targets.clear(); this.activateListeners(); ui.notifications.info(this.prompt, { localize: true }); diff --git a/src/module/rules/rule-element/mark-token/rule-element.ts b/src/module/rules/rule-element/mark-token/rule-element.ts index 7575b596c76..eab91a39672 100644 --- a/src/module/rules/rule-element/mark-token/rule-element.ts +++ b/src/module/rules/rule-element/mark-token/rule-element.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item"; import { TokenDocumentPF2e } from "@scene"; import { ErrorPF2e, sluggify } from "@util"; @@ -13,7 +14,7 @@ class MarkTokenRuleElement extends RuleElementPF2e { /** The uuid of the token */ tokenUUID: string | null; - constructor(data: MarkTokenSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: MarkTokenSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); if (typeof data.slug === "string" && data.slug.length > 0) { diff --git a/src/module/rules/rule-element/martial-proficiency.ts b/src/module/rules/rule-element/martial-proficiency.ts index 40c13e9e4a7..57451e7376c 100644 --- a/src/module/rules/rule-element/martial-proficiency.ts +++ b/src/module/rules/rule-element/martial-proficiency.ts @@ -1,5 +1,5 @@ import { RuleElementPF2e, RuleElementData, RuleElementSource, RuleElementOptions } from "."; -import { CharacterPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e } from "@actor"; import { MartialProficiency } from "@actor/character/data"; import { ActorType } from "@actor/data"; import { ItemPF2e } from "@item"; @@ -14,7 +14,7 @@ class MartialProficiencyRuleElement extends RuleElementPF2e { /** Predication test for whether a weapon matches this proficiency */ definition: PredicatePF2e; - constructor(data: MartialProficiencySource, item: Embedded, options?: RuleElementOptions) { + constructor(data: MartialProficiencySource, item: ItemPF2e, options?: RuleElementOptions) { data.priority = 9; data.immutable = Boolean(data.immutable ?? true); data.value ??= 1; diff --git a/src/module/rules/rule-element/multiple-attack-penalty.ts b/src/module/rules/rule-element/multiple-attack-penalty.ts index 59c3fc1b364..3f197a2122b 100644 --- a/src/module/rules/rule-element/multiple-attack-penalty.ts +++ b/src/module/rules/rule-element/multiple-attack-penalty.ts @@ -1,7 +1,7 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item"; -import { RuleElementOptions } from "./"; import { MAPSynthetic } from "../synthetics"; -import { RuleElementPF2e } from "./"; +import { RuleElementOptions, RuleElementPF2e } from "./"; import { RuleElementSource } from "./data"; /** @@ -10,7 +10,7 @@ import { RuleElementSource } from "./data"; export class MultipleAttackPenaltyRuleElement extends RuleElementPF2e { private selector: string; - constructor(data: MAPSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: MAPSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); if (typeof data.selector === "string") { diff --git a/src/module/rules/rule-element/roll-note.ts b/src/module/rules/rule-element/roll-note.ts index e133359aa0c..7cb63c2a7cf 100644 --- a/src/module/rules/rule-element/roll-note.ts +++ b/src/module/rules/rule-element/roll-note.ts @@ -5,6 +5,7 @@ import { DegreeOfSuccessString, DEGREE_OF_SUCCESS_STRINGS } from "@system/degree import { isObject } from "@util"; import { ArrayField, ModelPropsFromSchema, StringField } from "types/foundry/common/data/fields.mjs"; import { BracketedValue, RuleElementOptions, RuleElementPF2e, RuleElementSchema, RuleElementSource } from "./"; +import { ActorPF2e } from "@actor"; const { fields } = foundry.data; @@ -30,7 +31,7 @@ class RollNoteRuleElement extends RuleElementPF2e { /** The main text of the note */ text: string | BracketedValue; - constructor(source: RollNoteSource, item: Embedded, options?: RuleElementOptions) { + constructor(source: RollNoteSource, item: ItemPF2e, options?: RuleElementOptions) { super(source, item, options); if (this.#isValid(source)) { diff --git a/src/module/rules/rule-element/roll-option.ts b/src/module/rules/rule-element/roll-option.ts index c7e124881ca..1debbcaf043 100644 --- a/src/module/rules/rule-element/roll-option.ts +++ b/src/module/rules/rule-element/roll-option.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item"; import { PredicateField } from "@system/schema-data-fields"; import { ErrorPF2e, isObject } from "@util"; @@ -30,7 +31,7 @@ class RollOptionRuleElement extends RuleElementPF2e { */ toggleable: boolean | "totm"; - constructor(source: RollOptionSource, item: Embedded, options?: RuleElementOptions) { + constructor(source: RollOptionSource, item: ItemPF2e, options?: RuleElementOptions) { // This rule element behaves much like an override AE-like, so set its default priority to 50 super({ priority: CONST.ACTIVE_EFFECT_MODES.OVERRIDE * 10, ...source }, item, options); diff --git a/src/module/rules/rule-element/roll-twice.ts b/src/module/rules/rule-element/roll-twice.ts index e2073ea3c20..130d175ba40 100644 --- a/src/module/rules/rule-element/roll-twice.ts +++ b/src/module/rules/rule-element/roll-twice.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item"; import { RuleElementSource } from "."; import { RollTwiceSynthetic } from "../synthetics"; @@ -12,7 +13,7 @@ export class RollTwiceRuleElement extends RuleElementPF2e { /** If the hosting item is an effect, remove or expire it after a matching roll is made */ removeAfterRoll = this.item.isOfType("effect"); - constructor(data: RollTwiceSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: RollTwiceSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); if (this.#isValid(data)) { diff --git a/src/module/rules/rule-element/sense.ts b/src/module/rules/rule-element/sense.ts index 1b6df660a36..6d957de2e61 100644 --- a/src/module/rules/rule-element/sense.ts +++ b/src/module/rules/rule-element/sense.ts @@ -1,10 +1,10 @@ -import { RuleElementPF2e, RuleElementData, RuleElementSource } from "./"; -import { CharacterPF2e, FamiliarPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e, FamiliarPF2e } from "@actor"; +import { CreatureSensePF2e, SENSE_ACUITIES, SENSE_TYPES, SenseAcuity, SenseType } from "@actor/creature/sense"; import { ActorType } from "@actor/data"; import { ItemPF2e } from "@item"; -import { CreatureSensePF2e, SenseAcuity, SenseType, SENSE_ACUITIES, SENSE_TYPES } from "@actor/creature/sense"; -import { RuleElementOptions } from "./base"; import { setHasElement, tupleHasValue } from "@util"; +import { RuleElementData, RuleElementPF2e, RuleElementSource } from "./"; +import { RuleElementOptions } from "./base"; /** * @category RuleElement @@ -16,7 +16,7 @@ export class SenseRuleElement extends RuleElementPF2e { private acuity: SenseAcuity; - constructor(data: SenseRuleElementSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: SenseRuleElementSource, item: ItemPF2e, options?: RuleElementOptions) { data.force ??= false; data.range ??= ""; data.acuity ??= "precise"; diff --git a/src/module/rules/rule-element/strike.ts b/src/module/rules/rule-element/strike.ts index 2a9398f9d32..2992c090440 100644 --- a/src/module/rules/rule-element/strike.ts +++ b/src/module/rules/rule-element/strike.ts @@ -1,4 +1,4 @@ -import { CharacterPF2e, NPCPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e, NPCPF2e } from "@actor"; import { ActorType } from "@actor/data"; import { ItemPF2e, WeaponPF2e } from "@item"; import { NPCAttackTrait } from "@item/melee/data"; @@ -34,7 +34,7 @@ const { fields } = foundry.data; class StrikeRuleElement extends RuleElementPF2e { protected static override validActorTypes: ActorType[] = ["character", "npc"]; - constructor(source: StrikeSource, item: Embedded, options?: RuleElementOptions) { + constructor(source: StrikeSource, item: ItemPF2e, options?: RuleElementOptions) { super(source, item, options); // Force a label of "Fist" if the `fist` shorthand is being used @@ -231,7 +231,7 @@ class StrikeRuleElement extends RuleElementPF2e { * Construct a `WeaponPF2e` instance for use as the synthetic strike * @param damageType The resolved damage type for the strike */ - #constructWeapon(damageType: DamageType): Embedded { + #constructWeapon(damageType: DamageType): WeaponPF2e { const source: PreCreate = deepClone({ _id: this.item.id, name: this.label, @@ -257,7 +257,7 @@ class StrikeRuleElement extends RuleElementPF2e { }, }); - return new WeaponPF2e(source, { parent: this.actor, pf2e: { ready: true } }) as Embedded; + return new WeaponPF2e(source, { parent: this.actor, pf2e: { ready: true } }) as WeaponPF2e; } } diff --git a/src/module/rules/rule-element/striking.ts b/src/module/rules/rule-element/striking.ts index 28a1c385fd6..0007e2c5331 100644 --- a/src/module/rules/rule-element/striking.ts +++ b/src/module/rules/rule-element/striking.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ActorType } from "@actor/data"; import { ItemPF2e, WeaponPF2e } from "@item"; import { getStrikingDice } from "@item/physical/runes"; @@ -9,7 +10,7 @@ export class StrikingRuleElement extends RuleElementPF2e { selector: string; - constructor(data: StrikingSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: StrikingSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); if (typeof data.selector === "string") { diff --git a/src/module/rules/rule-element/substitute-roll.ts b/src/module/rules/rule-element/substitute-roll.ts index 87fcbae15e8..d9d592ed963 100644 --- a/src/module/rules/rule-element/substitute-roll.ts +++ b/src/module/rules/rule-element/substitute-roll.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item"; import { sluggify, tupleHasValue } from "@util"; import { RuleElementSource } from "."; @@ -13,7 +14,7 @@ class SubstituteRollRuleElement extends RuleElementPF2e { /** The effect type of this substitution */ effectType: "fortune" | "misfortune"; - constructor(data: SubstituteRollSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: SubstituteRollSource, item: ItemPF2e, options?: RuleElementOptions) { data.slug ??= item.slug ?? sluggify(item.name); super(data, item, options); diff --git a/src/module/rules/rule-element/temp-hp.ts b/src/module/rules/rule-element/temp-hp.ts index 9d24583f732..55b1cd5439e 100644 --- a/src/module/rules/rule-element/temp-hp.ts +++ b/src/module/rules/rule-element/temp-hp.ts @@ -1,8 +1,9 @@ +import { ActorPF2e } from "@actor"; import { ActorType } from "@actor/data"; import { ItemPF2e } from "@item"; import { ChatMessagePF2e } from "@module/chat-message"; import { isObject } from "@util"; -import { RuleElementPF2e, RuleElementData, RuleElementSource } from "./"; +import { RuleElementData, RuleElementPF2e, RuleElementSource } from "./"; import { RuleElementOptions } from "./base"; /** @@ -11,7 +12,7 @@ import { RuleElementOptions } from "./base"; class TempHPRuleElement extends RuleElementPF2e { static override validActorTypes: ActorType[] = ["character", "npc", "familiar"]; - constructor(data: TempHPSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: TempHPSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); /** Whether the temporary hit points are immediately applied */ diff --git a/src/module/rules/rule-element/token-image.ts b/src/module/rules/rule-element/token-image.ts index 9f86b702a06..d9355bac748 100644 --- a/src/module/rules/rule-element/token-image.ts +++ b/src/module/rules/rule-element/token-image.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item"; import { BracketedValue, RuleElementOptions, RuleElementPF2e, RuleElementSource } from "./"; @@ -12,7 +13,7 @@ export class TokenImageRuleElement extends RuleElementPF2e { /** An optional scale adjustment */ scale?: number; - constructor(data: TokenImageSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: TokenImageSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); if (typeof data.value === "string" || this.isBracketedValue(data.value)) { diff --git a/src/module/rules/rule-element/token-light.ts b/src/module/rules/rule-element/token-light.ts index e4e388e824e..35b1eeee610 100644 --- a/src/module/rules/rule-element/token-light.ts +++ b/src/module/rules/rule-element/token-light.ts @@ -1,6 +1,7 @@ +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item"; import { isObject } from "@util"; -import { RuleElementPF2e, RuleElementData, RuleElementOptions } from "./"; +import { RuleElementData, RuleElementOptions, RuleElementPF2e } from "./"; import { RuleElementSource } from "./data"; /** @@ -8,7 +9,7 @@ import { RuleElementSource } from "./data"; * @category RuleElement */ class TokenLightRuleElement extends RuleElementPF2e { - constructor(data: RuleElementSource, item: Embedded, options?: RuleElementOptions) { + constructor(data: RuleElementSource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); this.validateData(); } diff --git a/src/module/rules/rule-element/weapon-potency.ts b/src/module/rules/rule-element/weapon-potency.ts index 4197aacd3a3..f5391427606 100644 --- a/src/module/rules/rule-element/weapon-potency.ts +++ b/src/module/rules/rule-element/weapon-potency.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { AutomaticBonusProgression as ABP } from "@actor/character/automatic-bonus-progression"; import { ActorType } from "@actor/data"; import { ItemPF2e, WeaponPF2e } from "@item"; @@ -13,7 +14,7 @@ export class WeaponPotencyRuleElement extends RuleElementPF2e { selector: string; - constructor(data: WeaponPotencySource, item: Embedded, options?: RuleElementOptions) { + constructor(data: WeaponPotencySource, item: ItemPF2e, options?: RuleElementOptions) { super(data, item, options); this.selector = String(data.selector); } diff --git a/src/module/rules/synthetics.ts b/src/module/rules/synthetics.ts index 541e8f31726..c1957f2dacc 100644 --- a/src/module/rules/synthetics.ts +++ b/src/module/rules/synthetics.ts @@ -1,3 +1,4 @@ +import { ActorPF2e } from "@actor"; import { DexterityModifierCapData } from "@actor/character/types"; import { MovementType, LabeledSpeed } from "@actor/creature/data"; import { CreatureSensePF2e } from "@actor/creature/sense"; @@ -35,11 +36,11 @@ interface RuleElementSynthetics { senses: SenseSynthetic[]; statisticsModifiers: ModifierSynthetics; strikeAdjustments: StrikeAdjustment[]; - strikes: Map>; + strikes: Map>; striking: Record; targetMarks: Map; toggles: RollOptionToggle[]; - tokenOverrides: DeepPartial> & { + tokenOverrides: DeepPartial> & { texture?: { src: VideoFilePath } | { src: VideoFilePath; scaleX: number; scaleY: number }; }; weaponPotency: Record; diff --git a/src/module/scene/ambient-light-document.ts b/src/module/scene/ambient-light-document.ts index f0498e58ab8..7622f2321c6 100644 --- a/src/module/scene/ambient-light-document.ts +++ b/src/module/scene/ambient-light-document.ts @@ -1,17 +1,18 @@ import { AmbientLightPF2e } from "@module/canvas"; import { ScenePF2e } from "."; -class AmbientLightDocumentPF2e extends AmbientLightDocument { +class AmbientLightDocumentPF2e< + TParent extends ScenePF2e | null = ScenePF2e | null +> extends AmbientLightDocument { /** Is this light actually a source of darkness? */ get isDarkness(): boolean { - return this.object.source.isDarkness; + return this.object?.source.isDarkness ?? false; } } -interface AmbientLightDocumentPF2e extends AmbientLightDocument { - readonly parent: ScenePF2e | null; - - get object(): AmbientLightPF2e; +interface AmbientLightDocumentPF2e + extends AmbientLightDocument { + get object(): AmbientLightPF2e | null; } export { AmbientLightDocumentPF2e }; diff --git a/src/module/scene/data.ts b/src/module/scene/data.ts index a6f1074b5f9..a6f94da7a9e 100644 --- a/src/module/scene/data.ts +++ b/src/module/scene/data.ts @@ -1,7 +1,11 @@ import { ZeroToTwo } from "@module/data"; -import type { ScenePF2e } from "."; -type SceneDataPF2e = foundry.data.SceneData; +interface SceneFlagsPF2e extends DocumentFlags { + pf2e: { + [key: string]: unknown; + syncDarkness: "enabled" | "disabled" | "default"; + }; +} enum LightLevels { DARKNESS = 1 / 4, @@ -10,4 +14,4 @@ enum LightLevels { type LightLevel = ZeroToTwo; -export { SceneDataPF2e, LightLevel, LightLevels }; +export { LightLevel, LightLevels, SceneFlagsPF2e }; diff --git a/src/module/scene/document.ts b/src/module/scene/document.ts index ebe1a87897c..775be74b018 100644 --- a/src/module/scene/document.ts +++ b/src/module/scene/document.ts @@ -1,4 +1,4 @@ -import { LightLevels, SceneDataPF2e } from "./data"; +import { LightLevels, SceneFlagsPF2e } from "./data"; import { SceneConfigPF2e } from "./sheet"; import { AmbientLightDocumentPF2e, MeasuredTemplateDocumentPF2e, TileDocumentPF2e, TokenDocumentPF2e } from "."; import { checkAuras } from "./helpers"; @@ -71,11 +71,7 @@ class ScenePF2e extends Scene { /* -------------------------------------------- */ /** Redraw auras if the scene was activated while being viewed */ - override _onUpdate( - changed: DeepPartial, - options: DocumentModificationContext, - userId: string - ): void { + override _onUpdate(changed: DeepPartial, options: SceneUpdateContext, userId: string): void { super._onUpdate(changed, options, userId); if (changed.active && canvas.scene === this) { @@ -87,25 +83,17 @@ class ScenePF2e extends Scene { } interface ScenePF2e extends Scene { + flags: SceneFlagsPF2e; + /** Added as debounced method: check for auras containing newly-placed or moved tokens */ checkAuras(): void; _sheet: SceneConfigPF2e | null; - readonly lights: foundry.abstract.EmbeddedCollection; - readonly templates: foundry.abstract.EmbeddedCollection; - readonly tokens: foundry.abstract.EmbeddedCollection; - readonly tiles: foundry.abstract.EmbeddedCollection; - - flags: { - pf2e: { - [key: string]: unknown; - syncDarkness: "enabled" | "disabled" | "default"; - }; - [key: string]: Record; - }; - - readonly data: SceneDataPF2e; + readonly lights: foundry.abstract.EmbeddedCollection>; + readonly templates: foundry.abstract.EmbeddedCollection>; + readonly tokens: foundry.abstract.EmbeddedCollection>; + readonly tiles: foundry.abstract.EmbeddedCollection>; get sheet(): SceneConfigPF2e; } diff --git a/src/module/scene/helpers.ts b/src/module/scene/helpers.ts index 8409bc863c6..abf4bb2c530 100644 --- a/src/module/scene/helpers.ts +++ b/src/module/scene/helpers.ts @@ -17,7 +17,7 @@ const checkAuras = foundry.utils.debounce(async function (this: ScenePF2e): Prom }); // Get all tokens in the scene, excluding additional tokens linked to a common actor - const tokens = this.tokens.reduce((list: Embedded[], token) => { + const tokens = this.tokens.reduce((list: TokenDocumentPF2e[], token) => { if (token.isLinked && list.some((t) => t.actor === token.actor)) { return list; } diff --git a/src/module/scene/measured-template-document.ts b/src/module/scene/measured-template-document.ts index 3384cbe6cc0..337dc7a5181 100644 --- a/src/module/scene/measured-template-document.ts +++ b/src/module/scene/measured-template-document.ts @@ -1,10 +1,11 @@ import { MeasuredTemplatePF2e } from "@module/canvas/measured-template"; import { ScenePF2e } from "./document"; -export class MeasuredTemplateDocumentPF2e extends MeasuredTemplateDocument {} +export class MeasuredTemplateDocumentPF2e< + TParent extends ScenePF2e | null = ScenePF2e | null +> extends MeasuredTemplateDocument {} -export interface MeasuredTemplateDocumentPF2e extends MeasuredTemplateDocument { - readonly parent: ScenePF2e | null; - - readonly _object: MeasuredTemplatePF2e | null; +export interface MeasuredTemplateDocumentPF2e + extends MeasuredTemplateDocument { + get object(): MeasuredTemplatePF2e | null; } diff --git a/src/module/scene/tile-document.ts b/src/module/scene/tile-document.ts index d7912a597a4..76f0a36c0fe 100644 --- a/src/module/scene/tile-document.ts +++ b/src/module/scene/tile-document.ts @@ -1 +1,3 @@ -export class TileDocumentPF2e extends TileDocument {} +import { ScenePF2e } from "./document"; + +export class TileDocumentPF2e extends TileDocument {} diff --git a/src/module/scene/token-document/aura/index.ts b/src/module/scene/token-document/aura/index.ts index 7ad7bff0322..6b8718eed50 100644 --- a/src/module/scene/token-document/aura/index.ts +++ b/src/module/scene/token-document/aura/index.ts @@ -1,17 +1,16 @@ +import { AuraColors, AuraData } from "@actor/types"; import { ItemTrait } from "@item/data/base"; +import { measureDistanceCuboid } from "@module/canvas"; import { EffectAreaSquare } from "@module/canvas/effect-area-square"; import { getAreaSquares } from "@module/canvas/token/aura/util"; import { ScenePF2e } from "@scene/document"; -import { TokenAuraData } from "./types"; import { TokenDocumentPF2e } from "../document"; -import { measureDistanceCuboid } from "@module/canvas"; -import { ActorPF2e } from "@actor"; -import { AuraColors, AuraData } from "@actor/types"; +import { TokenAuraData } from "./types"; class TokenAura implements TokenAuraData { slug: string; - token: Embedded; + token: TokenDocumentPF2e; level: number | null; @@ -42,7 +41,7 @@ class TokenAura implements TokenAuraData { } private get scene(): ScenePF2e { - return this.token.scene; + return this.token.scene!; } get bounds(): PIXI.Rectangle { @@ -68,12 +67,12 @@ class TokenAura implements TokenAuraData { } /** Does this aura overlap with (at least part of) a token? */ - containsToken(token: Embedded): boolean { + containsToken(token: TokenDocumentPF2e): boolean { // 1. If the token is the one emitting the aura, return true early if (token === this.token) return true; // 2. If this aura is out of range, return false early - if (this.token.object.distanceTo(token.object) > this.radius) return false; + if (this.token.object!.distanceTo(token.object!) > this.radius) return false; // 3. Check whether any aura square intersects the token's space return this.squares.some((s) => s.active && measureDistanceCuboid(s, token.bounds) === 0); @@ -88,8 +87,7 @@ class TokenAura implements TokenAuraData { if (!(auraActor && this.scene.isInFocus)) return; const tokensToCheck = (specific ? specific : this.token.scene?.tokens.contents ?? []).filter( - (t): t is Embedded & { actor: ActorPF2e } => - !!t.actor?.canUserModify(game.user, "update") + (t) => !!t.actor?.canUserModify(game.user, "update") ); const auraData = auraActor.auras.get(this.slug); @@ -98,7 +96,7 @@ class TokenAura implements TokenAuraData { const containedTokens = tokensToCheck.filter((t) => this.containsToken(t)); // Get unique actors and notify - const affectedActors = new Set(containedTokens.map((t) => t.actor)); + const affectedActors = new Set(containedTokens.flatMap((t) => t.actor ?? [])); const origin = { actor: auraActor, token: this.token }; for (const actor of affectedActors) { await actor.applyAreaEffects(auraData, origin); @@ -110,7 +108,7 @@ interface TokenAuraParams extends Omit { slug: string; level: number | null; radius: number; - token: Embedded; + token: TokenDocumentPF2e; traits: Set; } diff --git a/src/module/scene/token-document/data.ts b/src/module/scene/token-document/data.ts index de750eecdc5..a14f0b8492c 100644 --- a/src/module/scene/token-document/data.ts +++ b/src/module/scene/token-document/data.ts @@ -1,13 +1,10 @@ -import { TokenDocumentPF2e } from "@scene"; - -export interface TokenDataPF2e extends foundry.data.TokenData { - actorData: DeepPartial["_source"]>; - flags: { - pf2e: { - [key: string]: unknown; - linkToActorSize: boolean; - autoscale: boolean; - }; - [key: string]: Record; +interface TokenFlagsPF2e extends DocumentFlags { + pf2e: { + [key: string]: unknown; + linkToActorSize: boolean; + autoscale: boolean; }; + [key: string]: Record; } + +export { TokenFlagsPF2e }; diff --git a/src/module/scene/token-document/document.ts b/src/module/scene/token-document/document.ts index 6c92101578f..58b79d2afd2 100644 --- a/src/module/scene/token-document/document.ts +++ b/src/module/scene/token-document/document.ts @@ -1,15 +1,16 @@ import { ActorPF2e } from "@actor"; import { TokenPF2e } from "@module/canvas"; import { ScenePF2e, TokenConfigPF2e } from "@module/scene"; -import { TokenDataPF2e } from "./data"; import { ChatMessagePF2e } from "@module/chat-message"; import { CombatantPF2e, EncounterPF2e } from "@module/encounter"; import { PrototypeTokenPF2e } from "@actor/data/base"; import { TokenAura } from "./aura"; import { objectHasKey, sluggify } from "@util"; import { LightLevels } from "@scene/data"; +import { TokenFlagsPF2e } from "./data"; +import { DataModel } from "types/foundry/common/abstract/module.mjs"; -class TokenDocumentPF2e extends TokenDocument { +class TokenDocumentPF2e extends TokenDocument { /** Has this token gone through at least one cycle of data preparation? */ private initialized?: boolean; @@ -83,7 +84,7 @@ class TokenDocumentPF2e extends TokenDocum /** Is this token emitting light with a negative value */ get emitsDarkness(): boolean { - return this.data.brightLight < 0; + return this.light.bright < 0; } get rulesBasedVision(): boolean { @@ -156,7 +157,7 @@ class TokenDocumentPF2e extends TokenDocum slug: key, level: data.level, radius: data.radius, - token: this as Embedded, + token: this, traits: new Set(data.traits), colors: data.colors, }) @@ -235,8 +236,8 @@ class TokenDocumentPF2e extends TokenDocum if (tokenOverrides.light) { this.light = new foundry.data.LightData(tokenOverrides.light, { - parent: this, - } as unknown as this); + parent: this as unknown as DataModel, + }); } // Token dimensions from actor size @@ -368,7 +369,7 @@ class TokenDocumentPF2e extends TokenDocum /** Toggle token hiding if this token's actor is a loot actor */ protected override _onCreate( data: this["_source"], - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void { super._onCreate(data, options, userId); @@ -377,7 +378,7 @@ class TokenDocumentPF2e extends TokenDocum protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentUpdateContext, userId: string ): void { // Possibly re-render encounter tracker if token's `displayName` property has changed @@ -387,7 +388,7 @@ class TokenDocumentPF2e extends TokenDocum } // Workaround for actor-data preparation issue: release token if this is made unlinked while controlled - if (changed.actorLink === false && this.rendered && this.object.controlled) { + if (changed.actorLink === false && this.rendered && this.object?.controlled) { this.object.release(); } @@ -403,7 +404,7 @@ class TokenDocumentPF2e extends TokenDocum if (preUpdateIcon !== this.texture.src) { changed.texture = mergeObject(changed.texture ?? {}, { src: this.texture.src, - }) as foundry.data.TokenSource["texture"]; + }) as foundry.documents.TokenSource["texture"]; } delete changed.actorData; // Prevent upstream from doing so a second time } @@ -412,7 +413,7 @@ class TokenDocumentPF2e extends TokenDocum } /** Reinitialize vision if the actor's senses were updated directly */ - override _onUpdateBaseActor(update?: Record, options?: DocumentModificationContext): void { + override _onUpdateBaseActor(update?: Record, options?: DocumentModificationContext): void { super._onUpdateBaseActor(update, options); if (!this.isLinked) return; @@ -424,7 +425,7 @@ class TokenDocumentPF2e extends TokenDocum } } - protected override _onDelete(options: DocumentModificationContext, userId: string): void { + protected override _onDelete(options: DocumentModificationContext, userId: string): void { super._onDelete(options, userId); if (!this.actor) return; @@ -441,7 +442,7 @@ class TokenDocumentPF2e extends TokenDocum /** Re-render token placeable if REs have ephemerally changed any visuals of this token */ onActorEmbeddedItemChange(): void { - if (!(this.isLinked && this.rendered && this.object.visible)) return; + if (!(this.isLinked && this.rendered && this.object?.visible)) return; this.object.drawEffects().then(() => { const preUpdate = this.toObject(false); @@ -470,23 +471,16 @@ class TokenDocumentPF2e extends TokenDocum // Update combat tracker with changed effects if (this.combatant?.parent.active) ui.combat.render(); }); - this.object.drawBars(); + this.object?.drawBars(); } } -interface TokenDocumentPF2e extends TokenDocument { - readonly data: TokenDataPF2e; - - readonly _object: TokenPF2e | null; - - get object(): TokenPF2e; - - readonly parent: ScenePF2e | null; - - get combatant(): CombatantPF2e | null; - - _sheet: TokenConfigPF2e | null; +interface TokenDocumentPF2e extends TokenDocument { + flags: TokenFlagsPF2e; + get actor(): ActorPF2e | null; + get combatant(): CombatantPF2e | null; + get object(): TokenPF2e | null; get sheet(): TokenConfigPF2e; overlayEffect: ImageFilePath; diff --git a/src/module/scene/token-document/index.ts b/src/module/scene/token-document/index.ts index 65fe7cb63e8..a983c949c6e 100644 --- a/src/module/scene/token-document/index.ts +++ b/src/module/scene/token-document/index.ts @@ -1,3 +1,2 @@ export { TokenConfigPF2e } from "./sheet"; -export { TokenDataPF2e } from "./data"; export { TokenDocumentPF2e } from "./document"; diff --git a/src/module/system/action-macros/athletics/disarm.ts b/src/module/system/action-macros/athletics/disarm.ts index 505c461167d..ce4329d712d 100644 --- a/src/module/system/action-macros/athletics/disarm.ts +++ b/src/module/system/action-macros/athletics/disarm.ts @@ -1,10 +1,11 @@ +import { ActorPF2e } from "@actor"; import { ActionMacroHelpers, SkillActionOptions } from ".."; import { WeaponPF2e } from "@item"; export function disarm(options: SkillActionOptions) { const slug = options?.skill ?? "athletics"; const rollOptions = ["action:disarm"]; - ActionMacroHelpers.simpleRollActionCheck>({ + ActionMacroHelpers.simpleRollActionCheck>({ actors: options.actors, actionGlyph: options.glyph ?? "A", title: "PF2E.Actions.Disarm.Title", diff --git a/src/module/system/action-macros/athletics/grapple.ts b/src/module/system/action-macros/athletics/grapple.ts index 7fd07b5f018..6dfc192dfce 100644 --- a/src/module/system/action-macros/athletics/grapple.ts +++ b/src/module/system/action-macros/athletics/grapple.ts @@ -1,10 +1,11 @@ +import { ActorPF2e } from "@actor"; import { ActionMacroHelpers, SkillActionOptions } from ".."; import { WeaponPF2e } from "@item"; export function grapple(options: SkillActionOptions) { const slug = options?.skill ?? "athletics"; const rollOptions = ["action:grapple"]; - ActionMacroHelpers.simpleRollActionCheck>({ + ActionMacroHelpers.simpleRollActionCheck>({ actors: options.actors, actionGlyph: options.glyph ?? "A", title: "PF2E.Actions.Grapple.Title", diff --git a/src/module/system/action-macros/athletics/shove.ts b/src/module/system/action-macros/athletics/shove.ts index b096ffaf13c..395cdff3b79 100644 --- a/src/module/system/action-macros/athletics/shove.ts +++ b/src/module/system/action-macros/athletics/shove.ts @@ -1,10 +1,11 @@ +import { ActorPF2e } from "@actor"; import { ActionMacroHelpers, SkillActionOptions } from ".."; import { WeaponPF2e } from "@item"; export function shove(options: SkillActionOptions) { const slug = options?.skill ?? "athletics"; const rollOptions = ["action:shove"]; - ActionMacroHelpers.simpleRollActionCheck>({ + ActionMacroHelpers.simpleRollActionCheck>({ actors: options.actors, actionGlyph: options.glyph ?? "A", title: "PF2E.Actions.Shove.Title", diff --git a/src/module/system/action-macros/athletics/trip.ts b/src/module/system/action-macros/athletics/trip.ts index 368d429cd3e..7c91c91ffc1 100644 --- a/src/module/system/action-macros/athletics/trip.ts +++ b/src/module/system/action-macros/athletics/trip.ts @@ -1,12 +1,13 @@ -import { ActionMacroHelpers, SkillActionOptions } from ".."; +import { ActorPF2e } from "@actor"; import { MODIFIER_TYPE, ModifierPF2e } from "@actor/modifiers"; -import { extractModifierAdjustments } from "@module/rules/helpers"; import { WeaponPF2e } from "@item"; +import { extractModifierAdjustments } from "@module/rules/helpers"; +import { ActionMacroHelpers, SkillActionOptions } from ".."; export function trip(options: SkillActionOptions) { const slug = options?.skill ?? "athletics"; const rollOptions = ["action:trip"]; - ActionMacroHelpers.simpleRollActionCheck>({ + ActionMacroHelpers.simpleRollActionCheck>({ actors: options.actors, actionGlyph: options.glyph ?? "A", title: "PF2E.Actions.Trip.Title", diff --git a/src/module/system/action-macros/helpers.ts b/src/module/system/action-macros/helpers.ts index 9573702ec16..b7d07741ac3 100644 --- a/src/module/system/action-macros/helpers.ts +++ b/src/module/system/action-macros/helpers.ts @@ -60,7 +60,7 @@ export class ActionMacroHelpers { } } - static defaultCheckContext>( + static defaultCheckContext>( options: CheckContextOptions, data: { item?: ItemType; @@ -126,7 +126,7 @@ export class ActionMacroHelpers { }); } - static async simpleRollActionCheck>( + static async simpleRollActionCheck>( options: SimpleRollActionCheckOptions ): Promise { // figure out actors to roll for @@ -167,7 +167,7 @@ export class ActionMacroHelpers { options.traits, targetOptions, !!target?.object && - !!selfToken?.object.isFlanking(target.object, { reach: actor.getReach({ action }) }) + !!selfToken?.object?.isFlanking(target.object, { reach: actor.getReach({ action }) }) ? "self:flanking" : [], ].flat(); @@ -284,7 +284,7 @@ export class ActionMacroHelpers { } static target(): { - token: TokenDocumentPF2e | null; + token: TokenDocumentPF2e | null; actor: ActorPF2e | null; } { const targets = Array.from(game.user.targets).filter((t) => t.actor instanceof CreaturePF2e); @@ -296,7 +296,7 @@ export class ActionMacroHelpers { }; } - static getWeaponPotencyModifier(item: Embedded, selector: string): ModifierPF2e | null { + static getWeaponPotencyModifier(item: WeaponPF2e, selector: string): ModifierPF2e | null { const slug = "potency"; if (AutomaticBonusProgression.isEnabled(item.actor)) { return new ModifierPF2e({ @@ -319,7 +319,7 @@ export class ActionMacroHelpers { } } - static getApplicableEquippedWeapons(actor: ActorPF2e, trait: WeaponTrait): Embedded[] { + static getApplicableEquippedWeapons(actor: ActorPF2e, trait: WeaponTrait): WeaponPF2e[] { if (actor.isOfType("character")) { return actor.system.actions.flatMap((s) => (s.ready && s.item.traits.has(trait) ? s.item : [])); } else { diff --git a/src/module/system/action-macros/types.ts b/src/module/system/action-macros/types.ts index 07ac532d9f7..62fd9a26c9f 100644 --- a/src/module/system/action-macros/types.ts +++ b/src/module/system/action-macros/types.ts @@ -1,12 +1,12 @@ import { ActorPF2e, CreaturePF2e } from "@actor"; import { ModifierPF2e, StatisticModifier } from "@actor/modifiers"; +import { ItemPF2e } from "@item"; import { WeaponTrait } from "@item/weapon/types"; import { RollNotePF2e } from "@module/notes"; import { TokenDocumentPF2e } from "@scene"; import { CheckRoll, CheckType } from "@system/check"; import { CheckDC, DegreeOfSuccessString } from "@system/degree-of-success"; import { Statistic } from "@system/statistic"; -import { ItemPF2e } from "@item"; type ActionGlyph = "A" | "D" | "T" | "R" | "F" | "a" | "d" | "t" | "r" | "f" | 1 | 2 | 3 | "1" | "2" | "3"; @@ -16,7 +16,7 @@ class CheckContextError extends Error { } } -interface BuildCheckContextOptions> { +interface BuildCheckContextOptions> { actor: ActorPF2e; item?: ItemType; rollOptions: { @@ -26,20 +26,20 @@ interface BuildCheckContextOptions> { target?: ActorPF2e | null; } -interface BuildCheckContextResult> { +interface BuildCheckContextResult> { actor: ActorPF2e; item?: ItemType; rollOptions: string[]; target?: ActorPF2e | null; } -interface CheckContextOptions> { +interface CheckContextOptions> { actor: ActorPF2e; buildContext: (options: BuildCheckContextOptions) => BuildCheckContextResult; target?: ActorPF2e | null; } -interface CheckContext> { +interface CheckContext> { actor: ActorPF2e; item?: ItemType; modifiers?: ModifierPF2e[]; @@ -57,7 +57,7 @@ interface CheckResultCallback { roll: Rolled; } -interface SimpleRollActionCheckOptions> { +interface SimpleRollActionCheckOptions> { actors: ActorPF2e | ActorPF2e[] | undefined; actionGlyph: ActionGlyph | undefined; title: string; diff --git a/src/module/system/check/check.ts b/src/module/system/check/check.ts index 57dc9ba4d2e..bd90289082d 100644 --- a/src/module/system/check/check.ts +++ b/src/module/system/check/check.ts @@ -1,28 +1,28 @@ import { ActorPF2e, CharacterPF2e } from "@actor"; -import { AttackTarget } from "@actor/types"; import { StrikeData, TraitViewData } from "@actor/data/base"; +import { CheckModifier, StatisticModifier } from "@actor/modifiers"; +import { AttackTarget } from "@actor/types"; import { WeaponPF2e } from "@item"; import { ChatMessagePF2e } from "@module/chat-message"; import { ChatMessageSourcePF2e, CheckRollContextFlag, TargetFlag } from "@module/chat-message/data"; +import { isCheckContextFlag } from "@module/chat-message/helpers"; import { RollNotePF2e } from "@module/notes"; -import { TokenDocumentPF2e } from "@scene"; +import { ScenePF2e, TokenDocumentPF2e } from "@scene"; import { eventToRollParams } from "@scripts/sheet-util"; +import { StatisticDifficultyClass } from "@system/statistic"; import { ErrorPF2e, fontAwesomeIcon, objectHasKey, parseHTML, signedInteger, sluggify, traitSlugToObject } from "@util"; -import { CheckModifier, StatisticModifier } from "@actor/modifiers"; -import { CheckModifiersDialog } from "./dialog"; -import { CheckRoll, CheckRollDataPF2e } from "./roll"; import { + DEGREE_OF_SUCCESS_STRINGS, DegreeAdjustmentsRecord, DegreeOfSuccess, DegreeOfSuccessString, - DEGREE_OF_SUCCESS_STRINGS, } from "../degree-of-success"; import { LocalizePF2e } from "../localize"; import { TextEditorPF2e } from "../text-editor"; -import { CheckRollContext } from "./types"; +import { CheckModifiersDialog } from "./dialog"; +import { CheckRoll, CheckRollDataPF2e } from "./roll"; import { StrikeAttackRoll } from "./strike/attack-roll"; -import { isCheckContextFlag } from "@module/chat-message/helpers"; -import { StatisticDifficultyClass } from "@system/statistic"; +import { CheckRollContext } from "./types"; interface RerollOptions { heroPoint?: boolean; @@ -512,7 +512,7 @@ class CheckPF2e { if (targetActor?.token) return targetActor.token; // This is from a context flag: get the actor via UUID - return fromUuid(target.token); + return fromUuid(target.token) as Promise | null>; })(); const canSeeTokenName = (token ?? new TokenDocumentPF2e(targetActor?.prototypeToken.toObject() ?? {})) diff --git a/src/module/system/check/types.ts b/src/module/system/check/types.ts index 1eaa37b1587..988ffa44b6f 100644 --- a/src/module/system/check/types.ts +++ b/src/module/system/check/types.ts @@ -3,6 +3,7 @@ import { AttackTarget } from "@actor/types"; import { ItemPF2e } from "@item"; import { ZeroToTwo } from "@module/data"; import { RollSubstitution } from "@module/rules/synthetics"; +import { ScenePF2e } from "@scene"; import { TokenDocumentPF2e } from "@scene/token-document"; import { CheckDC, DegreeOfSuccessAdjustment } from "@system/degree-of-success"; import { BaseRollContext } from "@system/rolls"; @@ -30,9 +31,9 @@ interface CheckRollContext extends BaseRollContext { /** The actor which initiated this roll. */ actor?: ActorPF2e; /** The token which initiated this roll. */ - token?: TokenDocumentPF2e; + token?: TokenDocumentPF2e; /** The originating item of this attack, if any */ - item?: Embedded | null; + item?: ItemPF2e | null; /** Optional title of the roll options dialog; defaults to the check name */ title?: string; /** Optional DC data for the check */ diff --git a/src/module/system/conditions/manager.ts b/src/module/system/conditions/manager.ts index 462a9f92d82..1e67efebfa7 100644 --- a/src/module/system/conditions/manager.ts +++ b/src/module/system/conditions/manager.ts @@ -10,7 +10,7 @@ import { CONDITION_SLUGS } from "@actor/values"; export class ConditionManager { static #initialized = false; - static conditions: Map = new Map(); + static conditions: Map> = new Map(); /** Gets a list of condition slugs. */ static get conditionsSlugs(): string[] { @@ -20,11 +20,11 @@ export class ConditionManager { static async initialize(force = false): Promise { if (this.#initialized && !force) return; - type ConditionCollection = CompendiumCollection; + type ConditionCollection = CompendiumCollection>; const content = (await game.packs.get("pf2e.conditionitems")?.getDocuments()) ?? []; const entries = [ - ...content.map((c): [ConditionSlug, ConditionPF2e] => [c.slug, c]), - ...content.map((c): [ItemUUID, ConditionPF2e] => [c.uuid, c]), + ...content.map((c): [ConditionSlug, ConditionPF2e] => [c.slug, c]), + ...content.map((c): [ItemUUID, ConditionPF2e] => [c.uuid, c]), ]; this.conditions = new Map(entries); this.#initialized = true; @@ -34,9 +34,9 @@ export class ConditionManager { * Get a condition using the condition name. * @param slug A condition slug */ - static getCondition(slug: ConditionSlug, modifications?: DeepPartial): ConditionPF2e; - static getCondition(slug: string, modifications?: DeepPartial): ConditionPF2e | null; - static getCondition(slug: string, modifications: DeepPartial = {}): ConditionPF2e | null { + static getCondition(slug: ConditionSlug, modifications?: DeepPartial): ConditionPF2e; + static getCondition(slug: string, modifications?: DeepPartial): ConditionPF2e | null; + static getCondition(slug: string, modifications: DeepPartial = {}): ConditionPF2e | null { slug = sluggify(slug); if (!setHasElement(CONDITION_SLUGS, slug)) return null; @@ -72,7 +72,7 @@ export class ConditionManager { } } - static getFlattenedConditions(items: Embedded[]): FlattenedCondition[] { + static getFlattenedConditions(items: ConditionPF2e[]): FlattenedCondition[] { const flatteneds: Map = new Map(); for (const condition of items.sort(this.sortConditions)) { @@ -225,7 +225,7 @@ export class ConditionManager { return Array.from(flatteneds.values()); } - private static sortConditions(conditionA: ConditionPF2e, conditionB: ConditionPF2e): number { + private static sortConditions(conditionA: ConditionPF2e, conditionB: ConditionPF2e): number { return conditionA.slug === conditionB.slug ? conditionA.active ? -1 diff --git a/src/module/system/damage/damage.ts b/src/module/system/damage/damage.ts index e2dfe8fce5d..105fdc1fa7c 100644 --- a/src/module/system/damage/damage.ts +++ b/src/module/system/damage/damage.ts @@ -6,6 +6,7 @@ import { ZeroToThree } from "@module/data"; import { DEGREE_OF_SUCCESS_STRINGS } from "@system/degree-of-success"; import { DamageRoll, DamageRollDataPF2e } from "./roll"; import { DamageRollContext, DamageTemplate } from "./types"; +import { ActorPF2e } from "@actor"; /** Create a chat message containing a damage roll */ export class DamagePF2e { @@ -168,7 +169,8 @@ export class DamagePF2e { if (isStrike && item && self?.actor?.isOfType("character", "npc")) { const strikes: StrikeData[] = self.actor.system.actions; const strike = strikes.find( - (a): a is StrikeData & { item: ItemPF2e } => a.item?.id === item.id && a.item.slug === item.slug + (a): a is StrikeData & { item: ItemPF2e } => + a.item?.id === item.id && a.item.slug === item.slug ); if (strike) { diff --git a/src/module/system/effect-tracker.ts b/src/module/system/effect-tracker.ts index 7cc9d3cb3dc..214cc68979f 100644 --- a/src/module/system/effect-tracker.ts +++ b/src/module/system/effect-tracker.ts @@ -4,12 +4,12 @@ import type { EffectPF2e } from "@item/index"; import { EncounterPF2e } from "@module/encounter"; export class EffectTracker { - effects: Embedded[] = []; + effects: EffectPF2e[] = []; /** A separate collection of aura effects, including ones with unlimited duration */ - auraEffects: Collection> = new Collection(); + auraEffects: Collection> = new Collection(); - private insert(effect: Embedded, duration: { expired: boolean; remaining: number }): void { + private insert(effect: EffectPF2e, duration: { expired: boolean; remaining: number }): void { if (this.effects.length === 0) { this.effects.push(effect); } else { @@ -39,7 +39,7 @@ export class EffectTracker { } } - register(effect: Embedded): void { + register(effect: EffectPF2e): void { if (effect.fromAura && (canvas.ready || !effect.actor.isToken) && effect.id) { this.auraEffects.set(effect.uuid, effect); } @@ -73,7 +73,7 @@ export class EffectTracker { } } - unregister(toRemove: Embedded): void { + unregister(toRemove: EffectPF2e): void { this.effects = this.effects.filter((e) => e !== toRemove); this.auraEffects.delete(toRemove.uuid); } diff --git a/src/module/system/statistic/index.ts b/src/module/system/statistic/index.ts index 4d98b0ac4ab..23a5aa4b5a7 100644 --- a/src/module/system/statistic/index.ts +++ b/src/module/system/statistic/index.ts @@ -41,7 +41,7 @@ interface StatisticRollParameters { /** Additional modifiers */ modifiers?: ModifierPF2e[]; /** The originating item of this attack, if any */ - item?: Embedded | null; + item?: ItemPF2e | null; /** The roll mode (i.e., 'roll', 'blindroll', etc) to use when rendering this roll. */ rollMode?: RollMode | "roll"; /** Should the dialog be skipped */ diff --git a/src/module/system/tag-selector/base.ts b/src/module/system/tag-selector/base.ts index 00f14e5b12d..7ca93f7b64c 100644 --- a/src/module/system/tag-selector/base.ts +++ b/src/module/system/tag-selector/base.ts @@ -11,9 +11,7 @@ interface TagSelectorOptions extends FormApplicationOptions { customChoices?: Record; } -abstract class BaseTagSelector< - TDocument extends ActorPF2e | ItemPF2e = ActorPF2e | ItemPF2e -> extends FormApplication { +abstract class BaseTagSelector extends FormApplication { choices: Record; /** The object path to the property containing the tags */ @@ -72,8 +70,4 @@ abstract class BaseTagSelector< } } -interface BaseTagSelector { - options: FormApplicationOptions; -} - export { BaseTagSelector, TagSelectorOptions }; diff --git a/src/module/system/tag-selector/basic.ts b/src/module/system/tag-selector/basic.ts index 48d69f52a5f..f3aba0ffdc4 100644 --- a/src/module/system/tag-selector/basic.ts +++ b/src/module/system/tag-selector/basic.ts @@ -25,7 +25,7 @@ class TagSelectorBasic extends BaseTagSe /** Search string for filtering */ searchString = ""; - private filterTimeout: number | null = null; + #filterTimeout: number | null = null; protected objectProperty: string; @@ -142,11 +142,11 @@ class TagSelectorBasic extends BaseTagSe private onFilterResults(event: JQuery.TriggeredEvent) { event.preventDefault(); const input: HTMLFormElement = event.currentTarget; - if (this.filterTimeout) { - clearTimeout(this.filterTimeout); - this.filterTimeout = null; + if (this.#filterTimeout) { + clearTimeout(this.#filterTimeout); + this.#filterTimeout = null; } - this.filterTimeout = window.setTimeout(() => this.search(input.value), 100); + this.#filterTimeout = window.setTimeout(() => this.search(input.value), 100); } } diff --git a/src/module/user/document.ts b/src/module/user/document.ts index 93393864129..7be9030744a 100644 --- a/src/module/user/document.ts +++ b/src/module/user/document.ts @@ -1,7 +1,9 @@ import { ActorPF2e } from "@actor/base"; import { UserFlagsPF2e, UserSourcePF2e } from "./data"; +import { TokenPF2e } from "@module/canvas"; +import { ScenePF2e, TokenDocumentPF2e } from "@scene"; -class UserPF2e extends User { +class UserPF2e extends User { override prepareData(): void { super.prepareData(); if (canvas.ready && canvas.tokens.controlled.length > 0) { @@ -38,7 +40,7 @@ class UserPF2e extends User { protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentUpdateContext, userId: string ): void { super._onUpdate(changed, options, userId); @@ -55,9 +57,11 @@ class UserPF2e extends User { } } -interface UserPF2e extends User { - readonly _source: UserSourcePF2e; +interface UserPF2e extends User { + targets: Set>>; + character: ActorPF2e | null; flags: UserFlagsPF2e; + readonly _source: UserSourcePF2e; } interface UserSettingsPF2e { diff --git a/src/scripts/dice.ts b/src/scripts/dice.ts index 136a09fe5e4..def8a4438dd 100644 --- a/src/scripts/dice.ts +++ b/src/scripts/dice.ts @@ -44,13 +44,13 @@ class DicePF2e { rollType = "", }: { event: JQuery.Event; - item?: Embedded | null; + item?: ItemPF2e | null; parts: (string | number)[]; actor?: ActorPF2e; data: Record; template?: string; title: string; - speaker: foundry.data.ChatSpeakerSource; + speaker: foundry.documents.ChatSpeakerData; flavor?: Function; onClose?: Function; dialogOptions?: Partial; diff --git a/src/scripts/macros/hotbar.ts b/src/scripts/macros/hotbar.ts index 85f88e8de43..069dbf574c9 100644 --- a/src/scripts/macros/hotbar.ts +++ b/src/scripts/macros/hotbar.ts @@ -94,7 +94,7 @@ export async function rollActionMacro(itemId: string, _actionIndex: number, acti const content = await renderTemplate("systems/pf2e/templates/chat/strike-card.hbs", templateData); const token = actor.token ?? actor.getActiveTokens(true, true).shift() ?? null; - const chatData: Partial = { + const chatData: Partial = { speaker: ChatMessagePF2e.getSpeaker({ actor, token }), content, type: CONST.CHAT_MESSAGE_TYPES.OTHER, diff --git a/src/scripts/macros/raise-a-shield.ts b/src/scripts/macros/raise-a-shield.ts index 4640b38982f..9268aa1e5cd 100644 --- a/src/scripts/macros/raise-a-shield.ts +++ b/src/scripts/macros/raise-a-shield.ts @@ -1,4 +1,4 @@ -import { CharacterPF2e, NPCPF2e } from "@actor"; +import { ActorPF2e } from "@actor"; import { EffectPF2e } from "@item"; import { ChatMessagePF2e } from "@module/chat-message"; import { ActionDefaultOptions } from "@system/action-macros"; @@ -19,16 +19,17 @@ export async function raiseAShield(options: ActionDefaultOptions): Promise const actors = Array.isArray(options.actors) ? options.actors : [options.actors]; const actor = actors[0]; - if (actors.length > 1 || !(actor instanceof CharacterPF2e || actor instanceof NPCPF2e)) { + if (actors.length > 1 || !(actor && ["character", "npc"].includes(actor.type))) { ui.notifications.error(translations.BadArgs); return; } const shield = actor.heldShield; - const speaker = ChatMessagePF2e.getSpeaker({ actor: actor }); + const speaker = ChatMessagePF2e.getSpeaker({ actor }); const isSuccess = await (async (): Promise => { - const existingEffect = actor.itemTypes.effect.find((e) => e.flags.core?.sourceId === ITEM_UUID); + const effects: EffectPF2e[] = actor.itemTypes.effect; + const existingEffect = effects.find((e) => e.flags.core?.sourceId === ITEM_UUID); if (existingEffect) { await existingEffect.delete(); return false; diff --git a/src/scripts/macros/rest-for-the-night.ts b/src/scripts/macros/rest-for-the-night.ts index 2af367259ed..d38c5723ddf 100644 --- a/src/scripts/macros/rest-for-the-night.ts +++ b/src/scripts/macros/rest-for-the-night.ts @@ -1,4 +1,4 @@ -import { CharacterPF2e } from "@actor"; +import { ActorPF2e, CharacterPF2e } from "@actor"; import { ChatMessagePF2e } from "@module/chat-message"; import { ItemPF2e } from "@item"; import { ActionDefaultOptions } from "@system/action-macros"; @@ -30,7 +30,7 @@ export async function restForTheNight(options: ActionDefaultOptions): Promise[] = []; + const itemUpdates: EmbeddedDocumentUpdateData>[] = []; // A list of messages informing the user of updates made due to rest const statements: string[] = []; diff --git a/src/scripts/ui/inline-roll-links.ts b/src/scripts/ui/inline-roll-links.ts index 7ce01da2eb9..49cb8c6dbbd 100644 --- a/src/scripts/ui/inline-roll-links.ts +++ b/src/scripts/ui/inline-roll-links.ts @@ -12,7 +12,7 @@ import { MeasuredTemplatePF2e } from "@module/canvas"; const inlineSelector = ["action", "check", "effect-area", "repost"].map((keyword) => `[data-pf2-${keyword}]`).join(","); export const InlineRollLinks = { - injectRepostElement: (links: HTMLElement[], foundryDoc?: ClientDocument | ClientDocument2): void => { + injectRepostElement: (links: HTMLElement[], foundryDoc?: ClientDocument): void => { for (const link of links) { if (!foundryDoc || foundryDoc.isOwner) link.classList.add("with-repost"); @@ -37,7 +37,7 @@ export const InlineRollLinks = { } }, - listen: ($html: HTMLElement | JQuery, foundryDoc?: ClientDocument | ClientDocument2): void => { + listen: ($html: HTMLElement | JQuery, foundryDoc?: ClientDocument): void => { const html = $html instanceof HTMLElement ? $html : $html[0]!; if ($html instanceof HTMLElement) $html = $($html); @@ -219,7 +219,7 @@ export const InlineRollLinks = { } as const; if (typeof pf2EffectArea === "string") { - const templateData: DeepPartial = JSON.parse( + const templateData: DeepPartial = JSON.parse( pf2TemplateData ?? "{}" ); templateData.distance ||= Number(pf2Distance); diff --git a/src/scripts/ui/user-visibility.ts b/src/scripts/ui/user-visibility.ts index 6d4c89a9820..e096555bb2e 100644 --- a/src/scripts/ui/user-visibility.ts +++ b/src/scripts/ui/user-visibility.ts @@ -90,7 +90,7 @@ class UserVisibilityPF2e { type UserVisibility = "all" | "owner" | "gm" | "none"; interface ProcessOptions { - document?: ClientDocument | ClientDocument2 | null; + document?: ClientDocument | null; message?: ChatMessagePF2e; } diff --git a/src/util/uuid-utils.ts b/src/util/uuid-utils.ts index 6c14aa1ecb2..c4db148cd75 100644 --- a/src/util/uuid-utils.ts +++ b/src/util/uuid-utils.ts @@ -19,7 +19,7 @@ class UUIDUtils { static async fromUUIDs(uuids: Exclude[]): Promise; static async fromUUIDs(uuids: Exclude[]): Promise; static async fromUUIDs(uuids: string[]): Promise; - static async fromUUIDs(uuids: string[]): Promise { + static async fromUUIDs(uuids: string[]): Promise { const actors: ActorPF2e[] = []; const items: ItemPF2e[] = []; diff --git a/tests/fakes/fake-actor.ts b/tests/fakes/actor.ts similarity index 54% rename from tests/fakes/fake-actor.ts rename to tests/fakes/actor.ts index 88523db0059..b3367657321 100644 --- a/tests/fakes/fake-actor.ts +++ b/tests/fakes/actor.ts @@ -1,53 +1,58 @@ import type { ActorPF2e } from "@actor"; import { ActorSourcePF2e } from "@actor/data"; +import { ActorSystemSource } from "@actor/data/base"; import type { ItemPF2e } from "@item"; import { ItemSourcePF2e } from "@item/data"; import { ActiveEffectPF2e } from "@module/active-effect"; -import { FakeCollection } from "./fake-collection"; -import { FakeItem } from "./fake-item"; +import { ScenePF2e, TokenDocumentPF2e } from "@scene"; +import { MockCollection } from "./collection"; +import { MockItem } from "./item"; -export class FakeActor { - _data: ActorSourcePF2e; +export class MockActor { + _source: ActorSourcePF2e; - items: FakeCollection = new FakeCollection(); + readonly parent: TokenDocumentPF2e | null = null; - effects: FakeCollection = new FakeCollection(); + readonly items: MockCollection> = new MockCollection(); - _itemGuid = 1; + readonly effects: MockCollection> = new MockCollection(); - id: string; + _itemGuid = 1; constructor(data: ActorSourcePF2e, public options: DocumentConstructionContext = {}) { - this.id = data._id; - this._data = duplicate(data); - this._data.items ??= []; + this._source = duplicate(data); + this._source.items ??= []; this.prepareData(); } - get data() { - return this._data; + get id(): string | null { + return this._source._id; + } + + get name(): string { + return this._source.name; } - get name() { - return this._data.name; + get system(): ActorSystemSource { + return this._source.system; } prepareData(): void { - const sourceIds = this._data.items.map((source) => source._id); + const sourceIds = this._source.items.map((source) => source._id); for (const item of this.items) { if (!sourceIds.includes(item.id)) { this.items.delete(item.id); } } - for (const source of this._data.items) { + for (const source of this._source.items) { const item = this.items.get(source._id); if (item) { - (item as any)._data = duplicate(source); + (item as { _source: object })._source = duplicate(source); } else { this.items.set( source._id, - new FakeItem(source, { parent: this as unknown as ActorPF2e }) as unknown as ItemPF2e + new MockItem(source, { parent: this as unknown as ActorPF2e }) as unknown as ItemPF2e ); } } @@ -56,14 +61,14 @@ export class FakeActor { update(changes: Record) { delete changes.items; for (const [k, v] of Object.entries(changes)) { - global.setProperty(this._data, k, v); + global.setProperty(this._source, k, v); } this.prepareData(); } static async updateDocuments( updates: DocumentUpdateData[] = [], - _context: DocumentModificationContext = {} + _context: DocumentModificationContext> = {} ): Promise { return updates.flatMap((update) => { const actor = game.actors.find((actor) => actor.id === update._id); @@ -71,9 +76,9 @@ export class FakeActor { const itemUpdates = (update.items ?? []) as DeepPartial[]; delete update.items; - mergeObject(actor.data, update); + mergeObject(actor._source, update); for (const partial of itemUpdates) { - const source = (actor as any)._data.items.find( + const source = actor._source.items.find( (maybeSource: ItemSourcePF2e) => maybeSource._id === partial._id ); if (source) mergeObject(source, partial); @@ -86,32 +91,36 @@ export class FakeActor { async updateEmbeddedDocuments(type: string, data: any[]): Promise { for (const changes of data) { if (type === "Item") { - const source = this.data.items.find((itemData: ItemSourcePF2e) => itemData._id === changes._id); + const source = this._source.items.find((i) => i._id === changes._id); if (source) mergeObject(source, changes); } } this.prepareData(); } - async createEmbeddedDocuments(type: string, data: any[], _context: DocumentModificationContext): Promise { + async createEmbeddedDocuments( + type: string, + data: ItemSourcePF2e[], + _context: DocumentModificationContext + ): Promise { if (type === "Item") { for (const source of data) { source._id = `item${this._itemGuid}`; this._itemGuid += 1; - this._data.items.push(source); + this._source.items.push(source); } } this.prepareData(); } - async deleteEmbeddedDocuments(type: string, data: string[]): Promise { + async deleteEmbeddedDocuments(type: string, ids: string[]): Promise { if (type === "Item") { - this._data.items = this._data.items.filter((source: { _id: string }) => !data.includes(source._id)); + this._source.items = this._source.items.filter((source: { _id: string }) => !ids.includes(source._id)); } this.prepareData(); } - toObject(source = true) { - return source ? duplicate(this._data) : duplicate(this.data); + toObject() { + return duplicate(this._source); } } diff --git a/tests/fakes/chat-message.ts b/tests/fakes/chat-message.ts new file mode 100644 index 00000000000..f0439a154cd --- /dev/null +++ b/tests/fakes/chat-message.ts @@ -0,0 +1,7 @@ +export class MockChatMessage { + _source: foundry.documents.ChatMessageSource; + + constructor(data: foundry.documents.ChatMessageSource) { + this._source = duplicate(data); + } +} diff --git a/tests/fakes/fake-collection.ts b/tests/fakes/collection.ts similarity index 67% rename from tests/fakes/fake-collection.ts rename to tests/fakes/collection.ts index 4152c096954..e11c4fc1641 100644 --- a/tests/fakes/fake-collection.ts +++ b/tests/fakes/collection.ts @@ -1,10 +1,10 @@ -import type { ActorPF2e } from "@actor"; +import { ActorPF2e } from "@actor"; import { ItemPF2e } from "@item"; -import { FakeActor } from "./fake-actor"; -import { FakeItem } from "./fake-item"; +import { MockActor } from "./actor"; +import { MockItem } from "./item"; /** In Foundry this is actually a subclass of Map, but it incompatibly extends it at several points. */ -export class FakeCollection { +export class MockCollection { #map: Map; constructor(entries: [string, V][] = []) { @@ -27,7 +27,7 @@ export class FakeCollection { return this.#map.get(key) ?? null; } - set(key: string, value: V): FakeCollection { + set(key: string, value: V): MockCollection { this.#map.set(key, value); return this; } @@ -57,24 +57,24 @@ export class FakeCollection { } } -export class FakeWorldCollection extends FakeCollection {} +export class MockWorldCollection extends MockCollection {} -export class FakeActors extends FakeWorldCollection { +export class MockActors extends MockWorldCollection> { tokens: Record = {}; - documentClass = FakeActor as unknown as typeof ActorPF2e; + documentClass = MockActor as unknown as typeof ActorPF2e; - constructor(entries: [string, ActorPF2e][] = []) { + constructor(entries: [string, ActorPF2e][] = []) { super(entries); } } -export class FakeItems extends FakeWorldCollection { +export class MockItems extends MockWorldCollection> { tokens: Record = {}; - documentClass = FakeItem as unknown as typeof ItemPF2e; + documentClass = MockItem as unknown as typeof ItemPF2e; - constructor(entries: [string, ActorPF2e][] = []) { + constructor(entries: [string, ItemPF2e][] = []) { super(entries); } } diff --git a/tests/fakes/fake-chat-message.ts b/tests/fakes/fake-chat-message.ts deleted file mode 100644 index 1681335c674..00000000000 --- a/tests/fakes/fake-chat-message.ts +++ /dev/null @@ -1,7 +0,0 @@ -export class FakeChatMessage { - data: foundry.data.ChatMessageData; - - constructor(data: foundry.data.ChatMessageSource) { - this.data = duplicate(data) as unknown as foundry.data.ChatMessageData; - } -} diff --git a/tests/fakes/fake-macro.ts b/tests/fakes/fake-macro.ts deleted file mode 100644 index f4b352fc4e8..00000000000 --- a/tests/fakes/fake-macro.ts +++ /dev/null @@ -1,12 +0,0 @@ -// @ts-nocheck -export class FakeMacro { - _data: foundry.data.MacroData; - - constructor(data: foundry.data.MacroData) { - this._data = duplicate(data); - } - - get data() { - return this._data; - } -} diff --git a/tests/fakes/fake-roll-table.ts b/tests/fakes/fake-roll-table.ts deleted file mode 100644 index a8a32b31bb6..00000000000 --- a/tests/fakes/fake-roll-table.ts +++ /dev/null @@ -1,7 +0,0 @@ -export class FakeRollTable { - data: foundry.data.RollTableData; - - constructor(data: foundry.data.RollTableSource) { - this.data = duplicate(data) as unknown as foundry.data.RollTableData; - } -} diff --git a/tests/fakes/fake-token.ts b/tests/fakes/fake-token.ts deleted file mode 100644 index 9f64e992314..00000000000 --- a/tests/fakes/fake-token.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ActorPF2e } from "@actor/base"; -import { ScenePF2e } from "@module/scene"; -import { TokenDocumentPF2e } from "@module/scene/token-document"; - -export class FakeToken { - _actor: ActorPF2e | null; - parent: ScenePF2e | null; - data: foundry.data.TokenData; - - constructor(data: foundry.data.TokenSource, context: { parent?: ScenePF2e | null; actor?: ActorPF2e | null } = {}) { - this.data = duplicate(data) as foundry.data.TokenData; - this.parent = context.parent ?? null; - this._actor = context.actor ?? null; - } - - get actor() { - return this._actor; - } - - get scene() { - return this.parent; - } - - get id() { - return this.data._id; - } - - get name() { - return this.data.name; - } - - update(changes: EmbeddedDocumentUpdateData, context: DocumentModificationContext = {}) { - changes["_id"] = this.id; - this.scene?.updateEmbeddedDocuments("Token", [changes], context); - } -} diff --git a/tests/fakes/fake-user.ts b/tests/fakes/fake-user.ts deleted file mode 100644 index c7e715f1cb0..00000000000 --- a/tests/fakes/fake-user.ts +++ /dev/null @@ -1,33 +0,0 @@ -interface FakeUserData { - name: string; - _id: string; - flags: { - PF2e?: { - settings?: { - quickD20roll?: boolean; - }; - }; - }; -} - -export class FakeUser { - _data: FakeUserData; - constructor(data: FakeUserData) { - this._data = duplicate(data); - } - - get data(): FakeUserData { - return this._data; - } - - get name(): string { - return this._data.name; - } - - async update(changes: Record): Promise { - for (const [k, v] of Object.entries(changes)) { - global.setProperty(this._data, k, v); - } - return this; - } -} diff --git a/tests/fakes/fake-item.ts b/tests/fakes/item.ts similarity index 64% rename from tests/fakes/fake-item.ts rename to tests/fakes/item.ts index 35172d849a0..b5b3a671648 100644 --- a/tests/fakes/fake-item.ts +++ b/tests/fakes/item.ts @@ -2,30 +2,26 @@ import type { ActorPF2e } from "@actor"; import type { ItemPF2e } from "@item"; import { ItemSourcePF2e } from "@item/data"; -export class FakeItem { - _data: ItemSourcePF2e; +export class MockItem { + readonly _source: ItemSourcePF2e; - parent: ActorPF2e | null = null; + readonly parent: ActorPF2e | null; constructor(data: ItemSourcePF2e, public options: DocumentConstructionContext = {}) { - this._data = duplicate(data); + this._source = duplicate(data); this.parent = options.parent ?? null; } get id(): string { - return this.data._id; - } - - get data() { - return this._data; + return this._source._id; } get name() { - return this._data.name; + return this._source.name; } get system() { - return this._data.system; + return this._source.system; } get level(): number | null { @@ -45,23 +41,23 @@ export class FakeItem { } static async updateDocuments( - updates: DocumentUpdateData[] = [], - _context: DocumentModificationContext = {} - ): Promise { + updates: DocumentUpdateData>[] = [], + _context: DocumentModificationContext = {} + ): Promise[]> { return updates.flatMap((update) => { const item = game.items.find((item) => item.id === update._id); - if (item) mergeObject(item.data, update); + if (item) mergeObject(item._source, update); return item ?? []; }); } update(changes: object) { for (const [k, v] of Object.entries(changes)) { - global.setProperty(this._data, k, v); + global.setProperty(this._source, k, v); } } - toObject(source = true) { - return source ? duplicate(this._data) : duplicate(this.data); + toObject(): ItemSourcePF2e { + return duplicate(this._source); } } diff --git a/tests/fakes/journal-entry.ts b/tests/fakes/journal-entry.ts index 238c6477ea9..17ccd83edf5 100644 --- a/tests/fakes/journal-entry.ts +++ b/tests/fakes/journal-entry.ts @@ -1,10 +1,9 @@ -// @ts-nocheck -export class FakeJournalEntry { - _source: foundry.data.JournalEntrySource; +export class MockJournalEntry { + _source: foundry.documents.JournalEntrySource; readonly pages: object[] = []; - constructor(source: foundry.data.JournalEntrySource) { + constructor(source: foundry.documents.JournalEntrySource) { this._source = duplicate(source); this.pages = source.pages; } diff --git a/tests/fakes/macro.ts b/tests/fakes/macro.ts new file mode 100644 index 00000000000..c06aa53fa95 --- /dev/null +++ b/tests/fakes/macro.ts @@ -0,0 +1,7 @@ +export class MockMacro { + readonly _source: foundry.documents.MacroSource; + + constructor(data: foundry.documents.MacroSource) { + this._source = duplicate(data); + } +} diff --git a/tests/fakes/roll-table.ts b/tests/fakes/roll-table.ts new file mode 100644 index 00000000000..22191815404 --- /dev/null +++ b/tests/fakes/roll-table.ts @@ -0,0 +1,7 @@ +export class MockRollTable { + readonly _source: foundry.documents.RollTableSource; + + constructor(data: foundry.documents.RollTableSource) { + this._source = duplicate(data); + } +} diff --git a/tests/fakes/scene.ts b/tests/fakes/scene.ts index bf433ded09f..ed6ea4d1ba1 100644 --- a/tests/fakes/scene.ts +++ b/tests/fakes/scene.ts @@ -2,7 +2,7 @@ import { FoundryUtils } from "tests/utils"; -export class FakeScene { +export class MockScene { data: Partial & { _id: string; name: string }; constructor(data: Partial) { this.data = { _id: FoundryUtils.randomID(), name: "", ...data } as any; diff --git a/tests/fakes/token.ts b/tests/fakes/token.ts new file mode 100644 index 00000000000..990b5278a48 --- /dev/null +++ b/tests/fakes/token.ts @@ -0,0 +1,37 @@ +import { ActorPF2e } from "@actor/base"; +import { ScenePF2e, TokenDocumentPF2e } from "@module/scene"; + +export class MockToken { + actor: ActorPF2e | null; + readonly parent: ScenePF2e | null; + readonly _source: foundry.documents.TokenSource; + + constructor( + data: foundry.documents.TokenSource, + context: { parent?: ScenePF2e | null; actor?: ActorPF2e | null } = {} + ) { + this._source = duplicate(data); + this.parent = context.parent ?? null; + this.actor = context.actor ?? null; + } + + get id(): string { + return this._source._id; + } + + get name(): string { + return this._source.name; + } + + get scene(): this["parent"] { + return this.parent; + } + + update( + changes: EmbeddedDocumentUpdateData>, + context: SceneEmbeddedModificationContext> = {} + ) { + changes["_id"] = this.id; + this.scene?.updateEmbeddedDocuments("Token", [changes], context); + } +} diff --git a/tests/fakes/user.ts b/tests/fakes/user.ts new file mode 100644 index 00000000000..0f71e26fa00 --- /dev/null +++ b/tests/fakes/user.ts @@ -0,0 +1,20 @@ +import { UserSourcePF2e } from "@module/user/data"; + +export class MockUser { + readonly _source: UserSourcePF2e; + + constructor(data: UserSourcePF2e) { + this._source = duplicate(data); + } + + get name(): string { + return this._source.name; + } + + async update(changes: Record): Promise { + for (const [k, v] of Object.entries(changes)) { + global.setProperty(this._source, k, v); + } + return this; + } +} diff --git a/tests/module/migration.test.ts b/tests/module/migration.test.ts index c7063c4dbb4..a63c7869d05 100644 --- a/tests/module/migration.test.ts +++ b/tests/module/migration.test.ts @@ -4,21 +4,21 @@ import { populateFoundryUtilFunctions } from "../fixtures/foundryshim"; import { ActorSourcePF2e, CharacterSource } from "@actor/data"; import { MigrationRunner } from "@module/migration/runner"; import { MigrationBase } from "@module/migration/base"; -import { FakeActor } from "tests/fakes/fake-actor"; -import { FakeItem } from "tests/fakes/fake-item"; -import { FakeMacro } from "tests/fakes/fake-macro"; -import { FakeRollTable } from "tests/fakes/fake-roll-table"; -import { FakeUser } from "tests/fakes/fake-user"; -import { FakeScene } from "tests/fakes/scene"; -import { FakeChatMessage } from "tests/fakes/fake-chat-message"; +import { MockActor } from "tests/fakes/actor"; +import { MockItem } from "tests/fakes/item"; +import { MockMacro } from "tests/fakes/macro"; +import { MockRollTable } from "tests/fakes/roll-table"; +import { MockUser } from "tests/fakes/user"; +import { MockScene } from "tests/fakes/scene"; +import { MockChatMessage } from "tests/fakes/chat-message"; import characterJSON from "../../packs/data/iconics.db/amiri-level-1.json"; import armorJSON from "../../packs/data/equipment.db/scale-mail.json"; -import { ArmorSource } from "@item/data"; +import { ArmorSource, ItemSourcePF2e } from "@item/data"; import { FoundryUtils } from "tests/utils"; -import { FakeActors, FakeCollection, FakeItems, FakeWorldCollection } from "tests/fakes/fake-collection"; +import { MockActors, MockCollection, MockItems, MockWorldCollection } from "tests/fakes/collection"; import { LocalizePF2e } from "@module/system/localize"; -import { FakeJournalEntry } from "tests/fakes/journal-entry"; +import { MockJournalEntry } from "tests/fakes/journal-entry"; const characterData = FoundryUtils.duplicate(characterJSON) as unknown as CharacterSource; characterData.effects = []; @@ -59,21 +59,21 @@ describe("test migration runner", () => { schema: 5, }, }, - actors: new FakeActors(), + actors: new MockActors(), i18n: { format: (stringId: string, data: object): string => {} }, - items: new FakeItems(), - journal: new FakeWorldCollection(), - macros: new FakeWorldCollection(), - messages: new FakeWorldCollection(), - tables: new FakeWorldCollection(), - users: new FakeWorldCollection(), - packs: new FakeCollection(), - scenes: new FakeWorldCollection(), + items: new MockItems(), + journal: new MockWorldCollection(), + macros: new MockWorldCollection(), + messages: new MockWorldCollection(), + tables: new MockWorldCollection(), + users: new MockWorldCollection(), + packs: new MockCollection(), + scenes: new MockWorldCollection(), }; (global as any).CONFIG = { - Actor: { documentClass: FakeActor }, - Item: { documentClass: FakeItem }, + Actor: { documentClass: MockActor }, + Item: { documentClass: MockItem }, }; (global as any).ui = { @@ -99,15 +99,15 @@ describe("test migration runner", () => { class ChangeAlignmentMigration extends MigrationBase { static version = 12; - async updateActor(actor: CharacterSource) { - actor.system.details.alignment.value = "CG"; + async updateActor(source: CharacterSource) { + source.system.details.alignment.value = "CG"; } } class UpdateItemName extends MigrationBase { static version = 13; - async updateItem(item: any) { - item.name = "updated"; + async updateItem(source: ItemSourcePF2e): Promise { + source.name = "updated"; } } @@ -139,14 +139,14 @@ describe("test migration runner", () => { test("expect previous version migrations don't run", async () => { settings.worldSchemaVersion = 20; - game.actors.set(characterData._id, new FakeActor(characterData)); + game.actors.set(characterData._id, new MockActor(characterData)); const migrationRunner = new MigrationRunner([new ChangeNameMigration()]); await migrationRunner.runMigration(); - expect(game.actors.contents[0]._data.name).not.toEqual("updated"); + expect(game.actors.contents[0].name).not.toEqual("updated"); }); test("expect update causes version to be updated", async () => { - game.actors.set(characterData._id, new FakeActor(characterData)); + game.actors.set(characterData._id, new MockActor(characterData)); MigrationRunner.LATEST_SCHEMA_VERSION = 12; const migrationRunner = new MigrationRunner([new ChangeNameMigration()]); @@ -155,25 +155,25 @@ describe("test migration runner", () => { }); test("expect updated actor name in world", async () => { - game.actors.set(characterData._id, new FakeActor(characterData)); + game.actors.set(characterData._id, new MockActor(characterData)); const migrationRunner = new MigrationRunner([new ChangeNameMigration()]); await migrationRunner.runMigration(); - expect(game.actors.contents[0]._data.name).toEqual("updated"); + expect(game.actors.contents[0].name).toEqual("updated"); }); test("expect update actor deep property", async () => { - game.actors.set(characterData._id, new FakeActor(characterData)); + game.actors.set(characterData._id, new MockActor(characterData)); const migrationRunner = new MigrationRunner([new ChangeAlignmentMigration()]); await migrationRunner.runMigration(); - expect(game.actors.contents[0]._data.system.details.alignment.value).toEqual("CG"); + expect(game.actors.contents[0].system.details.alignment.value).toEqual("CG"); }); test.skip("expect unlinked actor in scene gets migrated", async () => { characterData._id = "actor1"; - game.actors.set(characterData._id, new FakeActor(characterData)); - const scene = new FakeScene({}); + game.actors.set(characterData._id, new MockActor(characterData)); + const scene = new MockScene({}); scene.addToken({ _id: "token1", actorId: "actor1", @@ -184,32 +184,32 @@ describe("test migration runner", () => { const migrationRunner = new MigrationRunner([new ChangeNameMigration()]); await migrationRunner.runMigration(); - expect(game.scenes.contents[0].data.tokens[0].actorData.name).toEqual("updated"); + expect(game.scenes.contents[0].tokens[0].actorData.name).toEqual("updated"); }); test("update world actor item", async () => { - game.actors.set(characterData._id, new FakeActor(characterData)); + game.actors.set(characterData._id, new MockActor(characterData)); const migrationRunner = new MigrationRunner([new UpdateItemName()]); await migrationRunner.runMigration(); - expect(game.actors.contents[0]._data.items[0].name).toEqual("updated"); + expect(game.actors.contents[0].items.contents[0].name).toEqual("updated"); }); test("update world item", async () => { - game.items.set(armorData._id, new FakeItem(armorData)); + game.items.set(armorData._id, new MockItem(armorData)); const migrationRunner = new MigrationRunner([new UpdateItemName()]); await migrationRunner.runMigration(); - expect(game.items.contents[0]._data.name).toEqual("updated"); + expect(game.items.contents[0].name).toEqual("updated"); }); test("properties can be removed", async () => { - game.items.set(armorData._id, new FakeItem(armorData)); - game.items.contents[0]._data.system.someFakeProperty = 123123; + game.items.set(armorData._id, new MockItem(armorData)); + game.items.contents[0].system.someFakeProperty = 123123; const migrationRunner = new MigrationRunner([new RemoveItemProperty()]); await migrationRunner.runMigration(); - expect("someFakeProperty" in game.items.contents[0]._data.system).toEqual(false); + expect("someFakeProperty" in game.items.contents[0].system).toEqual(false); }); test("migrations run in sequence", async () => { @@ -222,18 +222,18 @@ describe("test migration runner", () => { class UpdateItemNameWithProp extends MigrationBase { static version = 14; - async updateItem(item: any) { + async updateItem(item: ItemSourcePF2e) { item.name = `${item.system.prop}`; } } - game.items.set(armorData._id, new FakeItem(armorData)); - game.items.contents[0]._data.system.prop = 123; + game.items.set(armorData._id, new MockItem(armorData)); + game.items.contents[0].system.prop = 123; const migrationRunner = new MigrationRunner([new ChangeItemProp(), new UpdateItemNameWithProp()]); await migrationRunner.runMigration(); - expect(game.items.contents[0]._data.system.prop).toEqual(456); - expect(game.items.contents[0]._data.name).toEqual("456"); + expect(game.items.contents[0].system.prop).toEqual(456); + expect(game.items.contents[0].name).toEqual("456"); }); test("migrations can remove items from actors", async () => { @@ -244,7 +244,7 @@ describe("test migration runner", () => { } } - game.actors.set(characterData._id, new FakeActor(characterData)); + game.actors.set(characterData._id, new MockActor(characterData)); expect(game.actors.contents[0].items.size).toBeGreaterThan(0); const migrationRunner = new MigrationRunner([new RemoveItemsFromActor()]); @@ -274,7 +274,7 @@ describe("test migration runner", () => { test("migrations can add items to actors", async () => { characterData.items = []; - const actor = new FakeActor(characterData); + const actor = new MockActor(characterData); game.actors.set(actor.id, actor); const migrationRunner = new MigrationRunner([new AddItemToActor()]); @@ -292,20 +292,20 @@ describe("test migration runner", () => { } test("migrations can reference previously added items", async () => { - game.actors.set(characterData._id, new FakeActor(characterData)); + game.actors.set(characterData._id, new MockActor(characterData)); const migrationRunner = new MigrationRunner([new AddItemToActor(), new SetActorPropertyToAddedItem()]); await migrationRunner.runMigration(); - expect(game.actors.contents[0]._data.system.sampleItemId).toEqual("item1"); + expect(game.actors.contents[0].system.sampleItemId).toEqual("item1"); }); test.skip("migrations can reference previously added items on tokens", async () => { characterData._id = "actor1"; game.actors.clear(); - game.actors.set(characterData._id, new FakeActor(characterData)); - game.actors.contents[0]._data.items = []; + game.actors.set(characterData._id, new MockActor(characterData)); + game.actors.contents[0]._source.items = []; - const scene = new FakeScene({}); + const scene = new MockScene({}); scene.addToken({ _id: "token1", actorId: "actor1", @@ -316,7 +316,7 @@ describe("test migration runner", () => { const migrationRunner = new MigrationRunner([new AddItemToActor(), new SetActorPropertyToAddedItem()]); await migrationRunner.runMigration(); - expect(game.actors.contents[0]._data.system.sampleItemId).toEqual("item2"); + expect(game.actors.contents[0].system.sampleItemId).toEqual("item2"); }); test("expect free migration function gets called", async () => { diff --git a/tests/setup.ts b/tests/setup.ts index 6b06e17c848..f4d6e34ef54 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -1,8 +1,8 @@ import * as path from "path"; import * as fs from "fs"; -import { FakeActor } from "./fakes/fake-actor"; -import { FakeItem } from "./fakes/fake-item"; -import { FakeToken } from "./fakes/fake-token"; +import { MockActor } from "./fakes/actor"; +import { MockItem } from "./fakes/item"; +import { MockToken } from "./fakes/token"; export const fetchSpell = (name: string) => { const spellsDb = "./packs/data/spells.db/"; @@ -251,9 +251,9 @@ function mergeObject( globalThis.mergeObject = mergeObject; globalThis.duplicate = duplicate; globalThis.deepClone = deepClone; -(global as any).Actor = FakeActor; -(global as any).Item = FakeItem; -(global as any).Token = FakeToken; +(global as any).Actor = MockActor; +(global as any).Item = MockItem; +(global as any).Token = MockToken; (global as any).FormApplication = class {}; (global as any).Roll = class {}; (global as any).Application = class {}; diff --git a/types/foundry/client/application/form-application/document-sheet-config.d.ts b/types/foundry/client/application/form-application/document-sheet-config.d.ts index ce2f6ee1d1b..d20f8d49a2f 100644 --- a/types/foundry/client/application/form-application/document-sheet-config.d.ts +++ b/types/foundry/client/application/form-application/document-sheet-config.d.ts @@ -1,7 +1,7 @@ export {}; declare global { - interface DocumentSheetConfigData + interface DocumentSheetConfigData extends FormApplicationData { isGM: boolean; object: TDocument; @@ -19,7 +19,7 @@ declare global { } /** Document Sheet Configuration Application */ - class DocumentSheetConfig extends FormApplication { + class DocumentSheetConfig extends FormApplication { static override get defaultOptions(): FormApplicationOptions; /** An array of pending sheet assignments which are submitted before other elements of the framework are ready. */ @@ -45,7 +45,7 @@ declare global { */ static initializeSheets(): void; - protected static _getDocumentTypes(cls: ClientDocument, types?: string[]): string[]; + protected static _getDocumentTypes(cls: foundry.abstract.Document, types?: string[]): string[]; /** * Register a sheet class as a candidate which can be used to display documents of a given type @@ -57,10 +57,10 @@ declare global { * @param [options.types] An array of document types for which this sheet should be used * @param [options.makeDefault] Whether to make this sheet the default for provided types */ - static registerSheet( - documentClass: ConstructorOf, + static registerSheet }>( + documentClass: ConstructorOf, scope: string, - sheetClass: ConstructorOf, + sheetClass: ConstructorOf, options?: RegisterSheetOptions ): void; @@ -74,10 +74,10 @@ declare global { * @param sheetClass A defined Application class used to render the sheet * @param types An Array of types for which this sheet should be removed */ - static unregisterSheet( - documentClass: ConstructorOf, + static unregisterSheet }>( + documentClass: ConstructorOf, scope: string, - sheetClass: ConstructorOf, + sheetClass: ConstructorOf, options?: { types: string[] } ): void; diff --git a/types/foundry/client/application/form-application/document-sheet/active-effect-config.d.ts b/types/foundry/client/application/form-application/document-sheet/active-effect-config.d.ts index 016429426a7..b2b01c149c6 100644 --- a/types/foundry/client/application/form-application/document-sheet/active-effect-config.d.ts +++ b/types/foundry/client/application/form-application/document-sheet/active-effect-config.d.ts @@ -16,8 +16,11 @@ declare global { ]; } - interface ActiveEffectConfigData - extends DocumentSheetData { + interface ActiveEffectConfigData< + TDocument extends ActiveEffect< + Actor | null> | Item | null> | null> | null + > + > extends DocumentSheetData { effect: TDocument; isActorEffect: boolean; isItemEffect: boolean; @@ -25,12 +28,14 @@ declare global { modes: Record; } - class ActiveEffectConfig extends DocumentSheet { - /** @override */ - static get defaultOptions(): ActiveEffectConfigOptions; + class ActiveEffectConfig< + TDocument extends ActiveEffect< + Actor | null> | Item | null> | null> | null + > + > extends DocumentSheet { + static override get defaultOptions(): ActiveEffectConfigOptions; - /** @override */ - getData(options?: DocumentSheetOptions): ActiveEffectConfigData; + override getData(options?: DocumentSheetOptions): ActiveEffectConfigData; /** * Provide centralized handling of mouse clicks on control buttons. @@ -45,10 +50,6 @@ declare global { */ private _addEffectChange(button: HTMLElement): HTMLElement; - /** @override */ - protected _updateObject( - event: Event, - formData: Record & { changes?: foundry.data.EffectChangeData[] } - ): Promise; + protected override _updateObject(event: Event, formData: Record): Promise; } } diff --git a/types/foundry/client/application/form-application/document-sheet/actor-sheet.d.ts b/types/foundry/client/application/form-application/document-sheet/actor-sheet.d.ts index f9acdf0b150..fc10cc8fea0 100644 --- a/types/foundry/client/application/form-application/document-sheet/actor-sheet.d.ts +++ b/types/foundry/client/application/form-application/document-sheet/actor-sheet.d.ts @@ -2,15 +2,16 @@ export {}; declare global { interface ActorSheetOptions extends DocumentSheetOptions { - token: TokenDocument | null; + token: TokenDocument | null; } - interface ActorSheetData extends DocumentSheetData { + interface ActorSheetData | null>> + extends DocumentSheetData { actor: any; data: any; items: any; cssClass: "editable" | "locked"; - effects: RawObject[]; + effects: RawObject>[]; limited: boolean; options: ActorSheetOptions; } @@ -24,10 +25,10 @@ declare global { * @param actor The Actor instance being displayed within the sheet. * @param options Additional application configuration options. */ - class ActorSheet extends DocumentSheet< - TActor, - ActorSheetOptions - > { + class ActorSheet< + TActor extends Actor | null>, + TItem extends Item | null> | null> = Item | null> | null> + > extends DocumentSheet { static override get defaultOptions(): ActorSheetOptions; override get id(): string; @@ -89,10 +90,10 @@ declare global { * @param data The data transfer extracted from the event * @return A data object which describes the result of the drop */ - protected _onDropActiveEffect( + protected _onDropActiveEffect>( event: ElementDragEvent, - data?: DropCanvasData<"ActiveEffect", D> - ): Promise; + data?: DropCanvasData<"ActiveEffect", TDocument> + ): Promise; /** * Handle dropping of an Actor data onto another Actor sheet @@ -124,13 +125,18 @@ declare global { * This method is factored out to allow downstream classes the opportunity to override item creation behavior. * @param itemData The item data requested for creation */ - protected _onDropItemCreate(itemData: TItem["_source"] | TItem["_source"][]): Promise; + protected _onDropItemCreate( + itemData: foundry.documents.ItemSource | foundry.documents.ItemSource[] + ): Promise[]>; /** * Handle a drop event for an existing embedded Item to sort that Item relative to its siblings * @param event * @param itemData */ - protected _onSortItem(event: ElementDragEvent, itemData: TItem["_source"]): Promise; + protected _onSortItem( + event: ElementDragEvent, + itemData: CollectionValue["_source"] + ): Promise[]>; } } diff --git a/types/foundry/client/application/form-application/document-sheet/base.d.ts b/types/foundry/client/application/form-application/document-sheet/base.d.ts index c7b813ebeff..d96e9d3822e 100644 --- a/types/foundry/client/application/form-application/document-sheet/base.d.ts +++ b/types/foundry/client/application/form-application/document-sheet/base.d.ts @@ -7,10 +7,10 @@ declare global { viewPermission: number; } - interface DocumentSheetData { + interface DocumentSheetData { cssClass: string; editable: boolean; - document: T; + document: TDocument; data: {}; limited: boolean; options: FormApplicationOptions; diff --git a/types/foundry/client/application/form-application/document-sheet/combatant-config.d.ts b/types/foundry/client/application/form-application/document-sheet/combatant-config.d.ts index ead63ae0a50..9c06f92f4e7 100644 --- a/types/foundry/client/application/form-application/document-sheet/combatant-config.d.ts +++ b/types/foundry/client/application/form-application/document-sheet/combatant-config.d.ts @@ -1,5 +1,5 @@ /** Configure or create a single Combatant within a Combat entity. */ -declare class CombatantConfig extends DocumentSheet { +declare class CombatantConfig> extends DocumentSheet { static override get defaultOptions(): DocumentSheetOptions; override get title(): string; diff --git a/types/foundry/client/application/form-application/document-sheet/index.d.ts b/types/foundry/client/application/form-application/document-sheet/index.d.ts new file mode 100644 index 00000000000..add36470a1b --- /dev/null +++ b/types/foundry/client/application/form-application/document-sheet/index.d.ts @@ -0,0 +1,15 @@ +import "./active-effect-config"; +import "./actor-sheet"; +import "./base"; +import "./combatant-config"; +import "./item-sheet"; +import "./journal-page-sheet"; +import "./journal-sheet"; +import "./macro-config"; +import "./note-config"; +import "./roll-table-config"; +import "./scene-config"; +import "./tile-config"; +import "./token-config"; +import "./user-config"; +import "./wall-config"; diff --git a/types/foundry/client/application/form-application/document-sheet/item-sheet.d.ts b/types/foundry/client/application/form-application/document-sheet/item-sheet.d.ts index 5bcaf4d40fa..21f3ec5d11e 100644 --- a/types/foundry/client/application/form-application/document-sheet/item-sheet.d.ts +++ b/types/foundry/client/application/form-application/document-sheet/item-sheet.d.ts @@ -9,7 +9,9 @@ * @param item The Item instance being displayed within the sheet. * @param [options] Additional options which modify the rendering of the item. */ -declare class ItemSheet extends DocumentSheet { +declare class ItemSheet< + TItem extends Item | null> | null> +> extends DocumentSheet { constructor(item: TItem, options?: Partial); static override get defaultOptions(): DocumentSheetOptions; @@ -33,7 +35,8 @@ declare class ItemSheet extends DocumentSheet override activateListeners(html: JQuery): void; } -declare interface ItemSheetData extends DocumentSheetData { +declare interface ItemSheetData | null> | null>> + extends DocumentSheetData { item: TItem; data: object; } diff --git a/types/foundry/client/application/form-application/document-sheet/journal-page-sheet.d.ts b/types/foundry/client/application/form-application/document-sheet/journal-page-sheet.d.ts index 45d0721aa47..f0e0a52046e 100644 --- a/types/foundry/client/application/form-application/document-sheet/journal-page-sheet.d.ts +++ b/types/foundry/client/application/form-application/document-sheet/journal-page-sheet.d.ts @@ -4,14 +4,14 @@ * @param [options] Application options. */ declare class JournalPageSheet< - TJournalEntryPage extends JournalEntryPage -> extends DocumentSheet { - constructor(object: TJournalEntryPage, options?: DocumentSheetOptions); + TDocument extends JournalEntryPage +> extends DocumentSheet { + constructor(object: TDocument, options?: DocumentSheetOptions); } declare class JournalTextPageSheet< - TJournalEntryPage extends JournalEntryPage -> extends JournalPageSheet { + TDocument extends JournalEntryPage +> extends JournalPageSheet { /* Declare the format that we edit text content in for this sheet so we can perform conversions as necessary. */ static get format(): number; @@ -19,4 +19,6 @@ declare class JournalTextPageSheet< isEditorDirty(): boolean; } -declare class JournalTextTinyMCESheet extends JournalPageSheet> {} +declare class JournalTextTinyMCESheet< + TDocument extends JournalEntryPage +> extends JournalPageSheet {} diff --git a/types/foundry/client/application/form-application/document-sheet/note-config.d.ts b/types/foundry/client/application/form-application/document-sheet/note-config.d.ts index 9ddd82a8d3c..a2fcc48ff7e 100644 --- a/types/foundry/client/application/form-application/document-sheet/note-config.d.ts +++ b/types/foundry/client/application/form-application/document-sheet/note-config.d.ts @@ -3,12 +3,11 @@ * @param note The Note object for which settings are being configured * @param options Additional Application options */ -declare class NoteConfig extends DocumentSheet { +declare class NoteConfig> extends DocumentSheet { /** * Extend the logic applied when the application is closed to clear any preview notes */ close(): Promise; - /** @override */ - protected _updateObject(event: Event, formData: {}): Promise; + protected override _updateObject(event: Event, formData: Record): Promise; } diff --git a/types/foundry/client/application/form-application/roll-table-config.d.ts b/types/foundry/client/application/form-application/document-sheet/roll-table-config.d.ts similarity index 100% rename from types/foundry/client/application/form-application/roll-table-config.d.ts rename to types/foundry/client/application/form-application/document-sheet/roll-table-config.d.ts diff --git a/types/foundry/client/application/form-application/document-sheet/tile-config.d.ts b/types/foundry/client/application/form-application/document-sheet/tile-config.d.ts new file mode 100644 index 00000000000..04d73155193 --- /dev/null +++ b/types/foundry/client/application/form-application/document-sheet/tile-config.d.ts @@ -0,0 +1,7 @@ +/** + * Tile Config Sheet + * @todo fill this in + */ +declare class TileConfig> extends DocumentSheet { + protected override _updateObject(event: Event, formData: Record): Promise; +} diff --git a/types/foundry/client/application/form-application/token-config.d.ts b/types/foundry/client/application/form-application/document-sheet/token-config.d.ts similarity index 92% rename from types/foundry/client/application/form-application/token-config.d.ts rename to types/foundry/client/application/form-application/document-sheet/token-config.d.ts index 51e35e477bf..b4423e5cb78 100644 --- a/types/foundry/client/application/form-application/token-config.d.ts +++ b/types/foundry/client/application/form-application/document-sheet/token-config.d.ts @@ -1,6 +1,6 @@ /** A Token Configuration Application */ declare class TokenConfig< - TDocument extends TokenDocument = TokenDocument, + TDocument extends TokenDocument, TOptions extends DocumentSheetOptions = DocumentSheetOptions > extends DocumentSheet { constructor(object: TDocument, options?: Partial); @@ -58,19 +58,19 @@ declare class TokenConfig< protected _onBarChange(event: Event): void; } -declare interface TokenConfigData extends DocumentSheetData { +declare interface TokenConfigData> extends DocumentSheetData { cssClasses: string; isPrototype: boolean; hasAlternates: boolean; alternateImages: string[]; - object: T["data"]; + object: TDocument; options: DocumentSheetOptions; gridUnits: string; barAttributes: string[]; bar1: string; bar2: string; displayModes: Record; - actors: T["actor"][]; + actors: TDocument["actor"][]; dispositions: Record; isGM: boolean; } diff --git a/types/foundry/client/application/form-application/document-sheet/user-config.d.ts b/types/foundry/client/application/form-application/document-sheet/user-config.d.ts index c03babcaafe..b6c08d09bfb 100644 --- a/types/foundry/client/application/form-application/document-sheet/user-config.d.ts +++ b/types/foundry/client/application/form-application/document-sheet/user-config.d.ts @@ -23,6 +23,6 @@ declare global { interface UserConfigData extends DocumentSheetData { user: User; - actors: Actor[]; + actors: Actor[]; } } diff --git a/types/foundry/client/application/form-application/image-popout.d.ts b/types/foundry/client/application/form-application/image-popout.d.ts index e80810ff229..4c37c434c8d 100644 --- a/types/foundry/client/application/form-application/image-popout.d.ts +++ b/types/foundry/client/application/form-application/image-popout.d.ts @@ -21,8 +21,8 @@ declare global { * // Share the image with other connected players * ip.share(); */ - class ImagePopout extends FormApplication< - ClientDocument, + class ImagePopout extends FormApplication< + TDocument, ImagePopoutOptions > { constructor(src: string, options?: Partial); diff --git a/types/foundry/client/application/form-application/index.d.ts b/types/foundry/client/application/form-application/index.d.ts new file mode 100644 index 00000000000..4555855bb6b --- /dev/null +++ b/types/foundry/client/application/form-application/index.d.ts @@ -0,0 +1,8 @@ +import "./base"; +import "./client-settings"; +import "./document-sheet"; +import "./document-sheet-config"; +import "./image-popout"; +import "./other"; +import "./permission"; +import "./placeables-config"; diff --git a/types/foundry/client/application/form-application/other.d.ts b/types/foundry/client/application/form-application/other.d.ts index 13d5edf76c8..9210dc9cde6 100644 --- a/types/foundry/client/application/form-application/other.d.ts +++ b/types/foundry/client/application/form-application/other.d.ts @@ -19,8 +19,10 @@ declare class FolderConfig extends FormApplication { * @param options Additional application rendering options * @param options.preview Configure a preview version of a sound which is not yet saved */ -declare class MeasuredTemplateConfig extends FormApplication { - protected override _updateObject(event: Event, formData: {}): Promise; +declare class MeasuredTemplateConfig< + TParent extends MeasuredTemplateDocument +> extends DocumentSheet { + protected override _updateObject(event: Event, formData: Record): Promise; } /** diff --git a/types/foundry/client/application/form-application/tile-config.d.ts b/types/foundry/client/application/form-application/tile-config.d.ts deleted file mode 100644 index b0022c29940..00000000000 --- a/types/foundry/client/application/form-application/tile-config.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Tile Config Sheet - * @todo fill this in - */ -declare class TileConfig extends FormApplication { - /** @override */ - protected _updateObject(event: Event, formData: Record): Promise; -} diff --git a/types/foundry/client/application/sidebar/sidebar-tab/chat-log.d.ts b/types/foundry/client/application/sidebar/sidebar-tab/chat-log.d.ts index 851dfaec180..4a44a8531b0 100644 --- a/types/foundry/client/application/sidebar/sidebar-tab/chat-log.d.ts +++ b/types/foundry/client/application/sidebar/sidebar-tab/chat-log.d.ts @@ -122,7 +122,7 @@ declare class ChatLog extends Si * @param message The original string of the message content * @return A Promise resolving to the prepared chat data object */ - protected processMessage(message: string): Promise; + protected processMessage(message: string): Promise; /** * Process messages which are posted using a dice-roll command @@ -134,7 +134,7 @@ declare class ChatLog extends Si protected _processDiceCommand( command: string, matches: RegExpMatchArray[], - chatData: DeepPartial, + chatData: DeepPartial, createOptions: ChatMessageModificationContext ): Promise; diff --git a/types/foundry/client/application/sidebar/sidebar-tab/combat-tracker.d.ts b/types/foundry/client/application/sidebar/sidebar-tab/combat-tracker.d.ts index e3aa5ea8b87..c362cdc7be3 100644 --- a/types/foundry/client/application/sidebar/sidebar-tab/combat-tracker.d.ts +++ b/types/foundry/client/application/sidebar/sidebar-tab/combat-tracker.d.ts @@ -105,7 +105,7 @@ declare class CombatTracker< * @param combatant The combatant data being modified * @return A Promise that resolves after all operations are complete */ - protected _onToggleDefeatedStatus(combatant: Combatant): Promise; + protected _onToggleDefeatedStatus(combatant: Combatant): Promise; /** * Handle mouse-down event on a combatant name in the tracker diff --git a/types/foundry/client/application/sidebar/sidebar-tab/sidebar-directory/actor-directory.d.ts b/types/foundry/client/application/sidebar/sidebar-tab/sidebar-directory/actor-directory.d.ts index 69d7fd861fa..d69a93db628 100644 --- a/types/foundry/client/application/sidebar/sidebar-tab/sidebar-directory/actor-directory.d.ts +++ b/types/foundry/client/application/sidebar/sidebar-tab/sidebar-directory/actor-directory.d.ts @@ -2,7 +2,7 @@ export {}; declare global { /** The sidebar directory which organizes and displays world-level Actor documents. */ - class ActorDirectory extends SidebarDirectory { + class ActorDirectory> extends SidebarDirectory { constructor(options: SidebarDirectoryOptions); static override documentName: "Actor"; diff --git a/types/foundry/client/application/sidebar/sidebar-tab/sidebar-directory/item-directory.d.ts b/types/foundry/client/application/sidebar/sidebar-tab/sidebar-directory/item-directory.d.ts index 65c6c4c3969..480a80a316e 100644 --- a/types/foundry/client/application/sidebar/sidebar-tab/sidebar-directory/item-directory.d.ts +++ b/types/foundry/client/application/sidebar/sidebar-tab/sidebar-directory/item-directory.d.ts @@ -2,7 +2,7 @@ export {}; declare global { /** The sidebar directory which organizes and displays world-level Item documents. */ - class ItemDirectory extends SidebarDirectory { + class ItemDirectory> extends SidebarDirectory { static override documentName: "Item"; protected override _canDragDrop(selector: string): boolean; diff --git a/types/foundry/client/collections/compendium-collection.d.ts b/types/foundry/client/collections/compendium-collection.d.ts index efc68982c82..a4d21f4581d 100644 --- a/types/foundry/client/collections/compendium-collection.d.ts +++ b/types/foundry/client/collections/compendium-collection.d.ts @@ -144,40 +144,45 @@ declare global { protected override _onCreateDocuments( documents: TDocument[], result: TDocument["_source"][], - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; protected override _onUpdateDocuments( documents: TDocument[], result: TDocument["_source"][], - options: DocumentModificationContext, + options: DocumentUpdateContext, userId: string ): void; protected override _onDeleteDocuments( documents: TDocument[], - result: TDocument["_source"][], - options: DocumentModificationContext, + result: string[], + options: DocumentModificationContext, userId: string ): void; /** Follow-up actions taken when Documents within this Compendium pack are modified */ - protected _onModifyContents(documents: TDocument[], options: DocumentModificationContext, userId: string): void; + protected _onModifyContents( + documents: TDocument[], + options: DocumentModificationContext, + userId: string + ): void; } type CompendiumDocumentType = (typeof CONST.COMPENDIUM_DOCUMENT_TYPES)[number]; type CompendiumUUID = `Compendium.${string}.${string}`; type DocumentUUID = WorldDocumentUUID | CompendiumUUID | TokenDocumentUUID; - function fromUuid( - uuid: CompendiumUUID, - relative?: CompendiumDocument - ): Promise; - function fromUuid( + function fromUuid(uuid: CompendiumUUID, relative?: CompendiumDocument): Promise; + function fromUuid( + uuid: TokenDocumentUUID, + relative?: foundry.abstract.Document + ): Promise | null>; + function fromUuid( uuid: string, - relative?: ClientDocument - ): Promise; + relative?: foundry.abstract.Document + ): Promise; /** * Retrieve a Document by its Universally Unique Identifier (uuid) synchronously. If the uuid resolves to a compendium @@ -190,7 +195,7 @@ declare global { function fromUuidSync( uuid: WorldDocumentUUID, relative?: ClientDocument | CompendiumIndexData | null - ): ClientDocument | null; + ): foundry.abstract.Document | null; function fromUuidSync( uuid: string, relative?: ClientDocument | CompendiumIndexData | null @@ -203,7 +208,7 @@ declare global { * @returns The Collection and the Document ID to resolve the parent document, as * well as the remaining Embedded Document parts, if any. */ - function _parseUuid(uuid: string, relative?: ClientDocument): ResolvedUUID; + function _parseUuid(uuid: string, relative?: foundry.abstract.Document): ResolvedUUID; interface ResolvedUUID { /** The parent collection. */ @@ -249,5 +254,5 @@ declare global { type CompendiumIndex = Collection; - type CompendiumDocument = Exclude; + type CompendiumDocument = Actor | Cards | Item | JournalEntry | Macro | Playlist | RollTable | Scene; } diff --git a/types/foundry/client/collections/document-collection.d.ts b/types/foundry/client/collections/document-collection.d.ts index a4fba199902..905e9e522ef 100644 --- a/types/foundry/client/collections/document-collection.d.ts +++ b/types/foundry/client/collections/document-collection.d.ts @@ -16,7 +16,7 @@ declare abstract class DocumentCollection; + get documentClass(): DocumentConstructorOf; /** A reference to the named Document class which is contained within this DocumentCollection. */ abstract get documentName(): string | null; @@ -45,7 +45,7 @@ declare abstract class DocumentCollection | ((document: TDocument) => DocumentUpdateData), condition?: ((document: TDocument) => boolean) | null, - options?: DocumentModificationContext + options?: DocumentModificationContext ): Promise; /** @@ -56,7 +56,7 @@ declare abstract class DocumentCollection, userId: string ): void; @@ -70,7 +70,7 @@ declare abstract class DocumentCollection, userId: string ): void; @@ -82,7 +82,7 @@ declare abstract class DocumentCollection, userId: string ): void; @@ -96,7 +96,7 @@ declare abstract class DocumentCollection, userId: string ): void; @@ -108,7 +108,7 @@ declare abstract class DocumentCollection, userId: string ): void; @@ -121,8 +121,8 @@ declare abstract class DocumentCollection, userId: string ): void; } diff --git a/types/foundry/client/collections/world-collection/actors.d.ts b/types/foundry/client/collections/world-collection/actors.d.ts index dd494b48fb3..9860ad6cc5d 100644 --- a/types/foundry/client/collections/world-collection/actors.d.ts +++ b/types/foundry/client/collections/world-collection/actors.d.ts @@ -11,7 +11,7 @@ * let actor = game.actors.get(actorId); * ``` */ -declare class Actors extends WorldCollection { +declare class Actors> extends WorldCollection { /** * A mapping of synthetic Token Actors which are currently active within the viewed Scene. * Each Actor is referenced by the Token.id. @@ -23,6 +23,6 @@ declare class Actors extends WorldCollection { override fromCompendium(document: TActor | TActor["_source"], options?: FromCompendiumOptions): TActor["_source"]; } -declare interface Actors extends WorldCollection { +declare interface Actors> extends WorldCollection { get documentName(): "Actor"; } diff --git a/types/foundry/client/collections/world-collection/base.d.ts b/types/foundry/client/collections/world-collection/base.d.ts index a85038cd340..f996e3eea54 100644 --- a/types/foundry/client/collections/world-collection/base.d.ts +++ b/types/foundry/client/collections/world-collection/base.d.ts @@ -59,7 +59,7 @@ declare global { pack: CompendiumCollection, id: string, updateData?: DocumentUpdateData, - options?: DocumentModificationContext + options?: DocumentModificationContext ): Promise; /** diff --git a/types/foundry/client/collections/world-collection/folders.d.ts b/types/foundry/client/collections/world-collection/folders.d.ts index c17c66b511f..5db88957f7d 100644 --- a/types/foundry/client/collections/world-collection/folders.d.ts +++ b/types/foundry/client/collections/world-collection/folders.d.ts @@ -2,8 +2,8 @@ * The Collection of Folder documents which exist within the active World. * This Collection is accessible within the Game object as game.folders. */ -declare class Folders extends WorldCollection { - constructor(data?: foundry.data.FolderSource[]); +declare class Folders extends WorldCollection { + constructor(data?: foundry.documents.FolderSource[]); protected _expanded: Record; diff --git a/types/foundry/client/collections/world-collection/items.d.ts b/types/foundry/client/collections/world-collection/items.d.ts index 9d763927fcf..11f669f3d85 100644 --- a/types/foundry/client/collections/world-collection/items.d.ts +++ b/types/foundry/client/collections/world-collection/items.d.ts @@ -5,6 +5,6 @@ * @see {@link Item} The Item document * @see {@link ItemDirectory} The ItemDirectory sidebar directory */ -declare class Items extends WorldCollection { +declare class Items> extends WorldCollection { static override documentName: "Item"; } diff --git a/types/foundry/client/collections/world-collection/playlists.d.ts b/types/foundry/client/collections/world-collection/playlists.d.ts index 674a5958c2d..47e4689d5c2 100644 --- a/types/foundry/client/collections/world-collection/playlists.d.ts +++ b/types/foundry/client/collections/world-collection/playlists.d.ts @@ -6,11 +6,9 @@ * @see {@link PlaylistDirectory} The PlaylistDirectory sidebar directory */ declare class Playlists extends WorldCollection { - /** @override */ - constructor(data?: foundry.data.PlaylistSoundData[]); + constructor(data?: foundry.documents.PlaylistSoundSource[]); - /** @override */ - static documentName: "Playlist"; + static override documentName: "Playlist"; /** Return the subset of Playlist entities which are currently playing */ get playing(): Playlist[]; diff --git a/types/foundry/client/collections/world-collection/scenes.d.ts b/types/foundry/client/collections/world-collection/scenes.d.ts index 05eab6efe7f..f91e3a65d8f 100644 --- a/types/foundry/client/collections/world-collection/scenes.d.ts +++ b/types/foundry/client/collections/world-collection/scenes.d.ts @@ -55,6 +55,6 @@ declare global { /* -------------------------------------------- */ /** @override */ - fromCompendium(document: TScene): foundry.data.SceneSource; + fromCompendium(document: TScene): foundry.documents.SceneSource; } } diff --git a/types/foundry/client/config.d.ts b/types/foundry/client/config.d.ts index 0ae9cc8559c..271ace7705b 100644 --- a/types/foundry/client/config.d.ts +++ b/types/foundry/client/config.d.ts @@ -2,22 +2,21 @@ import type * as TinyMCE from "tinymce"; declare global { interface Config< - TAmbientLightDocument extends AmbientLightDocument, - TActiveEffect extends ActiveEffect, - TActor extends Actor, - TActorDirectory extends ActorDirectory, + TAmbientLightDocument extends AmbientLightDocument, + TActiveEffect extends ActiveEffect, + TActor extends Actor, TChatLog extends ChatLog, TChatMessage extends ChatMessage, TCombat extends Combat, - TCombatant extends Combatant, + TCombatant extends Combatant, TCombatTracker extends CombatTracker, TCompendiumDirectory extends CompendiumDirectory, THotbar extends Hotbar, - TItem extends Item, + TItem extends Item, TMacro extends Macro, - TMeasuredTemplateDocument extends MeasuredTemplateDocument, - TTileDocument extends TileDocument, - TTokenDocument extends TokenDocument, + TMeasuredTemplateDocument extends MeasuredTemplateDocument, + TTileDocument extends TileDocument, + TTokenDocument extends TokenDocument, TWallDocument extends WallDocument, TScene extends Scene, TUser extends User, @@ -49,7 +48,7 @@ declare global { context?: DocumentConstructionContext ): TActor; }; - collection: ConstructorOf>; + collection: ConstructorOf>>; sheetClasses: Record< string, Record< @@ -183,8 +182,8 @@ declare global { /** Configuration for the AmbientLight embedded document type and its representation on the game Canvas */ AmbientLight: { documentClass: ConstructorOf; - objectClass: ConstructorOf; - layerClass: ConstructorOf; + objectClass: ConstructorOf>; + layerClass: ConstructorOf["layer"]>; }; /** Configuration for the ActiveEffect embedded document type */ @@ -217,26 +216,23 @@ declare global { rect: string; ray: string; }; - documentClass: new ( - data: PreCreate, - context?: DocumentConstructionContext - ) => TMeasuredTemplateDocument; - objectClass: ConstructorOf; - layerClass: ConstructorOf; + documentClass: ConstructorOf; + objectClass: ConstructorOf>; + layerClass: ConstructorOf["layer"]>; }; /** Configuration for the Tile embedded document type and its representation on the game Canvas */ Tile: { documentClass: ConstructorOf; - objectClass: ConstructorOf; - layerClass: ConstructorOf; + objectClass: ConstructorOf>; + layerClass: ConstructorOf>>; }; /** Configuration for the Token embedded document type and its representation on the game Canvas */ Token: { documentClass: ConstructorOf; - objectClass: ConstructorOf; - layerClass: ConstructorOf; + objectClass: ConstructorOf>; + layerClass: ConstructorOf["layer"]>; prototypeSheetClass: ConstructorOf; }; @@ -244,7 +240,7 @@ declare global { Wall: { documentClass: ConstructorOf; objectClass: ConstructorOf>; - layerClass: ConstructorOf; + layerClass: ConstructorOf["layer"]>; }; /* -------------------------------------------- */ @@ -294,10 +290,6 @@ declare global { }; }; layers: { - background: { - group: "primary"; - layerClass: typeof BackgroundLayer; - }; drawings: { group: "primary"; layerClass: typeof DrawingsLayer; @@ -308,11 +300,11 @@ declare global { }; walls: { group: "effects"; - layerClass: ConstructorOf; + layerClass: ConstructorOf["layer"]>; }; templates: { group: "primary"; - layerClass: ConstructorOf; + layerClass: ConstructorOf["layer"]>; }; notes: { group: "interface"; @@ -320,11 +312,11 @@ declare global { }; tokens: { group: "primary"; - layerClass: ConstructorOf; + layerClass: ConstructorOf["layer"]>; }; - foreground: { + tiles: { group: "primary"; - layerClass: typeof ForegroundLayer; + layerClass: typeof TilesLayer; }; sounds: { group: "interface"; @@ -332,7 +324,7 @@ declare global { }; lighting: { group: "effects"; - layerClass: ConstructorOf; + layerClass: ConstructorOf["layer"]>; }; controls: { group: "interface"; @@ -540,13 +532,13 @@ declare global { }; ui: { - actors: ConstructorOf; + actors: ConstructorOf>>; chat: ConstructorOf; combat: ConstructorOf; compendium: ConstructorOf; controls: typeof SceneControls; hotbar: ConstructorOf; - items: typeof ItemDirectory; + items: ConstructorOf>>; // journal: typeof JournalDirectory; // macros: typeof MacroDirectory; menu: typeof MainMenu; diff --git a/types/foundry/client/core/document-index.d.ts b/types/foundry/client/core/document-index.d.ts index 4455687ca81..e83430b81e4 100644 --- a/types/foundry/client/core/document-index.d.ts +++ b/types/foundry/client/core/document-index.d.ts @@ -10,7 +10,7 @@ declare global { * @property [pack] The pack ID. */ interface WordTreeEntry { - entry: ClientDocument | object; + entry: foundry.abstract.Document | object; documentName: WorldDocument["documentName"]; uuid: string; pack?: string; @@ -111,19 +111,19 @@ declare global { * Add an entry to the index. * @param doc The document entry. */ - addDocument(doc: ClientDocument): void; + addDocument(doc: foundry.abstract.Document): void; /** * Remove an entry from the index. * @param doc The document entry. */ - removeDocument(doc: ClientDocument): void; + removeDocument(doc: foundry.abstract.Document): void; /** * Replace an entry in the index with an updated one. * @param doc The document entry. */ - replaceDocument(doc: ClientDocument): void; + replaceDocument(doc: foundry.abstract.Document): void; /** * Add a leaf node to the word tree index. diff --git a/types/foundry/client/core/hooks.d.ts b/types/foundry/client/core/hooks.d.ts index 6055ebeeb9b..1e898b7862d 100644 --- a/types/foundry/client/core/hooks.d.ts +++ b/types/foundry/client/core/hooks.d.ts @@ -19,7 +19,11 @@ declare global { type HookParamsLightingRefresh = HookParameters<"lightingRefresh", [LightingLayer]>; type HookParamsPreCreateItem = HookParameters< "preCreateItem", - [PreCreate, DocumentModificationContext, string] + [ + PreCreate, + DocumentModificationContext | null> | null>, + string + ] >; type HooksParamsPreUpdateCombat = HookParameters< "preUpdateCombat", @@ -29,8 +33,8 @@ declare global { "preUpdateToken", [ Scene, - foundry.data.TokenData, - Partial, + foundry.documents.TokenSource, + DeepPartial, { diff: boolean; [key: string]: unknown }, string ] @@ -41,12 +45,12 @@ declare global { >; type HookParamsRenderChatMessage = HookParameters< "renderChatMessage", - [ChatMessage, JQuery, foundry.data.ChatMessageSource] + [ChatMessage, JQuery, foundry.documents.ChatMessageSource] >; type HookParamsTargetToken = HookParameters<"targetToken", [User, Token, boolean]>; - type HookParamsUpdate = HookParameters< + type HookParamsUpdate = HookParameters< `update${N}`, - [T, DocumentUpdateData, DocumentModificationContext] + [T, DocumentUpdateData, DocumentModificationContext] >; type HookParamsUpdateWorldTime = HookParameters<"updateWorldTime", [number, number]>; @@ -77,8 +81,8 @@ declare global { static on(...args: HookParamsRender): number; static on(...args: HookParamsRender): number; static on(...args: HookParamsRender): number; - static on(...args: HookParamsRender, "ActorDirectory">): number; - static on(...args: HookParamsRender, "ItemDirectory">): number; + static on(...args: HookParamsRender>, "ActorDirectory">): number; + static on(...args: HookParamsRender>, "ItemDirectory">): number; static on(...args: HookParamsRender): number; static on(...args: HookParamsRender): number; static on(...args: HookParamsRender): number; @@ -118,13 +122,13 @@ declare global { static once(...args: HookParamsPreCreateItem): number; static once(...args: HookParamsPreUpdateToken): number; static once(...args: HookParamsRenderChatMessage): number; - static once(...args: HookParamsRender, "ActorDirectory">): number; + static once(...args: HookParamsRender>, "ActorDirectory">): number; static once(...args: HookParamsRender): number; static once(...args: HookParamsRender): number; static once(...args: HookParamsRender): number; static once(...args: HookParamsRender): number; static once(...args: HookParamsRender): number; - static once(...args: HookParamsRender, "ItemDirectory">): number; + static once(...args: HookParamsRender>, "ItemDirectory">): number; static once( ...args: HookParamsRender>, "JournalPageSheet"> ): number; diff --git a/types/foundry/client/core/sorting.d.ts b/types/foundry/client/core/sorting.d.ts index 806ba12a934..89580adfd0c 100644 --- a/types/foundry/client/core/sorting.d.ts +++ b/types/foundry/client/core/sorting.d.ts @@ -19,11 +19,13 @@ declare class SortingHelpers { */ static performIntegerSort( source: T, - { - target, - siblings, - sortKey, - sortBefore, - }: { target?: T; siblings?: T[]; sortKey?: string; sortBefore?: boolean } + { target, siblings, sortKey, sortBefore }: SortingOptions ): { target: T; update: Record }[]; } + +declare interface SortingOptions { + target?: T; + siblings?: T[]; + sortKey?: string; + sortBefore?: boolean; +} diff --git a/types/foundry/client/core/text-editor.d.ts b/types/foundry/client/core/text-editor.d.ts index fbc92737de1..0ca6ed09497 100644 --- a/types/foundry/client/core/text-editor.d.ts +++ b/types/foundry/client/core/text-editor.d.ts @@ -146,10 +146,10 @@ declare global { * Toggle playing or stopping an embedded {@link PlaylistSound} link. * @param doc The PlaylistSound document to play/stop. */ - protected static _onPlaySound(doc: PlaylistSound): void; + protected static _onPlaySound(doc: PlaylistSound): void; /** Find all content links belonging to a given PlaylistSound. */ - protected static _getSoundContentLinks(doc: PlaylistSound): NodeListOf; + protected static _getSoundContentLinks(doc: PlaylistSound): NodeListOf; /** * Begin a Drag+Drop workflow for a dynamic content link diff --git a/types/foundry/client/documents/active-effect.d.ts b/types/foundry/client/documents/active-effect.d.ts index 177b932cad6..f7b13004c10 100644 --- a/types/foundry/client/documents/active-effect.d.ts +++ b/types/foundry/client/documents/active-effect.d.ts @@ -1,4 +1,4 @@ -import { ActiveEffectConstructor } from "./constructors"; +import { ClientBaseActiveEffect } from "./client-base-mixes.mjs"; declare global { /** @@ -6,17 +6,25 @@ declare global { * Each ActiveEffect belongs to the effects collection of its parent Document. * Each ActiveEffect contains a ActiveEffectData object which provides its source data. */ - class ActiveEffect extends ActiveEffectConstructor implements TemporaryEffect { + class ActiveEffect< + TParent extends + | Actor | null> + | Item | null> | null> + | null + > + extends ClientBaseActiveEffect + implements TemporaryEffect + { constructor( - data: PreCreate, - context?: DocumentConstructionContext + data: PreCreate, + context?: DocumentConstructionContext ); /** A cached reference to the source name to avoid recurring database lookups */ protected _sourceName: string | null; /** A cached reference to the ActiveEffectConfig instance which configures this effect */ - override _sheet: ActiveEffectConfig | null; + protected override _sheet: ActiveEffectConfig | null; /** Summarize the active effect duration */ get duration(): { @@ -65,7 +73,7 @@ declare global { * @param change The change data being applied * @return The resulting applied value */ - apply(actor: Actor, change: ApplicableChangeData): unknown; + apply(actor: Actor>, change: foundry.documents.EffectChangeSource): unknown; /** * Apply an ActiveEffect that uses an ADD application mode. @@ -80,7 +88,10 @@ declare global { * @param change The change data being applied * @return The resulting applied value */ - protected _applyAdd(actor: Actor, change: ApplicableChangeData): unknown; + protected _applyAdd( + actor: Actor>, + change: foundry.documents.EffectChangeSource + ): unknown; /** * Apply an ActiveEffect that uses a MULTIPLY application mode. @@ -89,7 +100,10 @@ declare global { * @param change The change data being applied * @return The resulting applied value */ - protected _applyMultiply(actor: Actor, change: ApplicableChangeData): unknown; + protected _applyMultiply( + actor: Actor>, + change: foundry.documents.EffectChangeSource + ): unknown; /** * Apply an ActiveEffect that uses an OVERRIDE application mode. @@ -98,7 +112,10 @@ declare global { * @param change The change data being applied * @return The resulting applied value */ - protected _applyOverride(actor: Actor, change: ApplicableChangeData): unknown; + protected _applyOverride( + actor: Actor>, + change: foundry.documents.EffectChangeSource + ): unknown; /** * Apply an ActiveEffect that uses an UPGRADE, or DOWNGRADE application mode. @@ -107,7 +124,10 @@ declare global { * @param change The change data being applied * @return The resulting applied value */ - protected _applyUpgrade(actor: Actor, change: ApplicableChangeData): unknown; + protected _applyUpgrade( + actor: Actor>, + change: foundry.documents.EffectChangeSource + ): unknown; /** * Apply an ActiveEffect that uses a CUSTOM application mode. @@ -115,7 +135,10 @@ declare global { * @param change The change data being applied * @return The resulting applied value */ - protected _applyCustom(actor: Actor, change: ApplicableChangeData): unknown; + protected _applyCustom( + actor: Actor>, + change: foundry.documents.EffectChangeSource + ): unknown; /** Get the name of the source of the Active Effect */ protected _getSourceName(): Promise; @@ -126,14 +149,17 @@ declare global { protected override _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: User ): Promise; } - interface ActiveEffect { - readonly parent: Actor | Item; - + interface ActiveEffect< + TParent extends + | Actor | null> + | Item | null> | null> + | null + > extends ClientBaseActiveEffect { disabled: boolean; icon: ImageFilePath; tint?: string; @@ -145,8 +171,4 @@ declare global { icon: ImageFilePath; tint?: string; } - - interface ApplicableChangeData extends foundry.data.EffectChangeSource { - effect: T; - } } diff --git a/types/foundry/client/documents/actor.d.ts b/types/foundry/client/documents/actor.d.ts index 9c4dff8de8a..84ef2965e04 100644 --- a/types/foundry/client/documents/actor.d.ts +++ b/types/foundry/client/documents/actor.d.ts @@ -1,4 +1,4 @@ -import { ActorConstructor } from "./constructors"; +import { ClientBaseActor } from "./client-base-mixes.mjs"; declare global { /** @@ -19,14 +19,11 @@ declare global { * @example Retrieve an existing Actor * let actor = game.actors.get(actorId); */ - class Actor< - TParent extends TokenDocument = TokenDocument, - TItemTypeMap extends ItemTypeMap = ItemTypeMap - > extends ActorConstructor { - constructor(data: PreCreate, context?: DocumentConstructionContext); + class Actor | null> extends ClientBaseActor { + constructor(data: PreCreate, context?: DocumentConstructionContext); /** An object that tracks which tracks the changes to the data model which were applied by active effects */ - overrides: DeepPartial & { token?: TParent["_source"] }; + overrides: Omit, "prototypeToken">; /** * A cached array of image paths which can be used for this Actor's token. @@ -41,7 +38,7 @@ declare global { get img(): ImageFilePath; /** Provide an object which organizes all embedded Item instances by their type */ - get itemTypes(): { [K in keyof TItemTypeMap]: Embedded[] }; + get itemTypes(): object; /** Test whether an Actor is a synthetic representation of a Token (if true) or a full Document (if false) */ get isToken(): boolean; @@ -70,25 +67,16 @@ declare global { * @param [document=false] Return the Document instance rather than the PlaceableObject * @return An array of Token instances in the current Scene which reference this Actor. */ - getActiveTokens(linked: boolean | undefined, document: true): Embedded>[]; - getActiveTokens(linked?: undefined, document?: undefined): NonNullable[]; getActiveTokens( linked?: boolean, document?: boolean - ): Embedded>[] | NonNullable[]; + ): Token>[] | TokenDocument[]; /** Prepare a data object which defines the data schema used by dice roll commands against this Actor */ getRollData(): Record; protected override _getSheetClass(): ConstructorOf>; - /** - * Create a new TokenData object which can be used to create a Token representation of the Actor. - * @param [data={}] Additional data, such as x, y, rotation, etc. for the created token data - * @return The created TokenData instance - */ - getTokenData(data?: DocumentModificationContext): Promise; - /** Get an Array of Token images which could represent this Actor */ getTokenImages(): Promise; @@ -130,37 +118,37 @@ declare global { protected override _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: User ): Promise; protected override _onUpdate( changed: DeepPartial, - options: DocumentUpdateContext, + options: DocumentUpdateContext, userId: string ): void; protected override _onCreateEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - documents: ActiveEffect[] | Item[], - result: foundry.data.ActiveEffectSource[] | foundry.data.ItemSource[], - options: DocumentModificationContext, + documents: ActiveEffect[] | Item[], + result: ActiveEffect["_source"][] | Item["_source"][], + options: DocumentModificationContext, userId: string ): void; protected override _onUpdateEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - documents: ActiveEffect[] | Item[], - result: foundry.data.ActiveEffectSource[] | foundry.data.ItemSource[], - options: DocumentModificationContext, + documents: ActiveEffect[] | Item[], + result: ActiveEffect["_source"][] | Item["_source"][], + options: DocumentUpdateContext, userId: string ): void; protected override _onDeleteEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - documents: ActiveEffect[] | Item[], - result: foundry.data.ActiveEffectSource[] | foundry.data.ItemSource[], - options: DocumentModificationContext, + documents: ActiveEffect[] | Item[], + result: string[], + options: DocumentModificationContext, userId: string ): void; @@ -171,57 +159,34 @@ declare global { protected _onEmbeddedDocumentChange(embeddedName: "Item" | "ActiveEffect"): void; } - interface Actor { - readonly effects: foundry.abstract.EmbeddedCollection; - readonly items: foundry.abstract.EmbeddedCollection; - readonly parent: TParent | null; + interface Actor | null> extends ClientBaseActor { + readonly effects: foundry.abstract.EmbeddedCollection>; + readonly items: foundry.abstract.EmbeddedCollection>; prototypeToken: foundry.data.PrototypeToken; - get collection(): Actors; - - _sheet: ActorSheet | null; + _sheet: ActorSheet | null; - get sheet(): ActorSheet; + get sheet(): ActorSheet; - get folder(): Folder | null; + get folder(): Folder> | null; deleteEmbeddedDocuments( embeddedName: "ActiveEffect", - dataId: string[], - context?: DocumentModificationContext - ): Promise; + ids: string[], + context?: DocumentModificationContext + ): Promise[]>; deleteEmbeddedDocuments( embeddedName: "Item", - dataId: string[], - context?: DocumentModificationContext - ): Promise; + ids: string[], + context?: DocumentModificationContext + ): Promise[]>; deleteEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - dataId: string[], - context?: DocumentModificationContext - ): Promise; - } - - namespace Actor { - function create( - this: ConstructorOf, - data: PreCreate, - context?: DocumentModificationContext - ): Promise; - function create( - this: ConstructorOf, - data: PreCreate[], - context?: DocumentModificationContext - ): Promise; - function create( - this: ConstructorOf, - data: PreCreate[] | PreCreate, - context?: DocumentModificationContext - ): Promise; + ids: string[], + context?: DocumentModificationContext + ): Promise[] | CollectionValue[]>; } type ActorUUID = `Actor.${string}` | CompendiumUUID; } - -type ItemTypeMap = Record; diff --git a/types/foundry/client/documents/ambient-light-document.d.ts b/types/foundry/client/documents/ambient-light-document.d.ts index 9cb86341a79..5398f7f4ad6 100644 --- a/types/foundry/client/documents/ambient-light-document.d.ts +++ b/types/foundry/client/documents/ambient-light-document.d.ts @@ -1,12 +1,12 @@ -import { AmbientLightDocumentConstructor } from "./constructors"; +import { CanvasBaseAmbientLight } from "./client-base-mixes.mjs"; declare global { - class AmbientLightDocument extends AmbientLightDocumentConstructor { + class AmbientLightDocument extends CanvasBaseAmbientLight { /** Is this ambient light source global in nature? */ get isGlobal(): boolean; } - interface AmbientLightDocument { - readonly parent: Scene | null; + interface AmbientLightDocument extends CanvasBaseAmbientLight { + get object(): AmbientLight | null; } } diff --git a/types/foundry/client/documents/ambient-sound-document.d.ts b/types/foundry/client/documents/ambient-sound-document.d.ts index c94ffc1210d..006de5b6320 100644 --- a/types/foundry/client/documents/ambient-sound-document.d.ts +++ b/types/foundry/client/documents/ambient-sound-document.d.ts @@ -1,9 +1,9 @@ -import { AmbientSoundDocumentConstructor } from "./constructors"; +import { CanvasBaseAmbientSound } from "./client-base-mixes.mjs"; declare global { - class AmbientSoundDocument extends AmbientSoundDocumentConstructor {} + class AmbientSoundDocument extends CanvasBaseAmbientSound {} - interface AmbientSoundDocument { - readonly parent: Scene | null; + interface AmbientSoundDocument extends CanvasBaseAmbientSound { + readonly _object: AmbientSound | null; } } diff --git a/types/foundry/client/documents/cards.d.ts b/types/foundry/client/documents/cards.d.ts index c5ad03ba8f3..9035c96314e 100644 --- a/types/foundry/client/documents/cards.d.ts +++ b/types/foundry/client/documents/cards.d.ts @@ -1,9 +1,9 @@ -import { CardsConstructor } from "./constructors"; +import { ClientBaseCards } from "./client-base-mixes.mjs"; declare global { /** * The client-side Cards document which extends the common BaseCards model. * Each Cards document contains CardsData which defines its data schema. */ - class Cards extends CardsConstructor {} + class Cards extends ClientBaseCards {} } diff --git a/types/foundry/client/documents/chat-message.d.ts b/types/foundry/client/documents/chat-message.d.ts index f162896a5c8..5c6962e20bc 100644 --- a/types/foundry/client/documents/chat-message.d.ts +++ b/types/foundry/client/documents/chat-message.d.ts @@ -1,4 +1,4 @@ -import { ChatMessageConstructor } from "./constructors"; +import { ClientBaseChatMessage } from "./client-base-mixes.mjs"; declare global { /** @@ -7,8 +7,8 @@ declare global { * @see {@link data.ChatMessageData} The ChatMessage data schema * @see {@link documents.Messages} The world-level collection of ChatMessage documents */ - class ChatMessage extends ChatMessageConstructor { - constructor(data: PreCreate, context?: DocumentConstructionContext); + class ChatMessage extends ClientBaseChatMessage { + constructor(data: PreCreate, context?: DocumentConstructionContext); flavor: string; @@ -50,15 +50,7 @@ declare global { * @param rollMode The rollMode preference to apply to this message data * @returns The modified ChatMessage data with rollMode preferences applied */ - static applyRollMode( - chatData: foundry.data.ChatMessageSource, - rollMode: RollMode - ): foundry.data.ChatMessageSource; - static applyRollMode(chatData: foundry.data.ChatMessageData, rollMode: RollMode): foundry.data.ChatMessageData; - static applyRollMode( - chatData: foundry.data.ChatMessageSource | foundry.data.ChatMessageData, - rollMode: RollMode - ): foundry.data.ChatMessageSource | foundry.data.ChatMessageData; + static applyRollMode(chatData: ChatMessage["_source"], rollMode: RollMode): ChatMessage["_source"]; /** * Update the data of a ChatMessage instance to apply a requested rollMode @@ -83,10 +75,10 @@ declare global { alias, }?: { scene?: Scene | null; - actor?: Actor | null; - token?: TokenDocument | null; + actor?: Actor | null> | null; + token?: TokenDocument | null; alias?: string; - }): foundry.data.ChatSpeakerSource; + }): foundry.documents.ChatSpeakerData; /** A helper to prepare the speaker object based on a target Token */ protected static _getSpeakerFromToken({ token, alias }: { token: Token; alias?: string }): { @@ -105,7 +97,7 @@ declare global { alias, }: { scene?: Scene; - actor: Actor; + actor: Actor | null>; alias?: string; }): { scene: string | null; @@ -134,7 +126,9 @@ declare global { * Obtain an Actor instance which represents the speaker of this message (if any) * @param speaker The speaker data object */ - static getSpeakerActor(speaker: DeepPartial): Actor | null; + static getSpeakerActor( + speaker: DeepPartial + ): Actor | null> | null; /** Obtain a data object used to evaluate any dice rolls associated with this particular chat message */ getRollData(): object; @@ -156,35 +150,35 @@ declare global { protected _renderRollContent: (messageData: ChatMessageRenderData) => Promise; protected override _preUpdate( - changed: DeepPartial, - options: DocumentModificationContext, - user: User + changed: DeepPartial, + options: DocumentModificationContext, + user: User ): Promise; protected override _onCreate( - data: foundry.data.ChatMessageSource, - options: DocumentModificationContext, + data: this["_source"], + options: DocumentModificationContext, userId: string ): void; protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; - protected override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; /** Export the content of the chat message into a standardized log format */ export(): string; } namespace ChatMessage { - function create( - this: ConstructorOf, - data: PreCreate[], + function create( + this: ConstructorOf, + data: PreCreate[], context?: ChatMessageModificationContext - ): Promise; + ): Promise; function create( this: ConstructorOf, data: PreCreate, @@ -195,16 +189,10 @@ declare global { data: PreCreate[] | PreCreate, context?: ChatMessageModificationContext ): Promise; - - const implementation: typeof ChatMessage; - } - - interface ChatMessageModificationContext extends DocumentModificationContext { - rollMode?: RollMode | "roll"; } interface ChatMessageRenderData { - message: RawObject; + message: RawObject; user: User; author: User; alias: string; diff --git a/types/foundry/client/documents/client-base-mixes.d.mts b/types/foundry/client/documents/client-base-mixes.d.mts new file mode 100644 index 00000000000..fad5402bba7 --- /dev/null +++ b/types/foundry/client/documents/client-base-mixes.d.mts @@ -0,0 +1,9834 @@ +declare class ClientBaseAmbientLight extends foundry.documents + .BaseAmbientLight { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +/** + * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be + * represented upon the game Canvas. + * @category - Mixins + */ +export class CanvasBaseAmbientLight extends ClientBaseAmbientLight { + /** A reference to the PlaceableObject instance which represents this Embedded Document. */ + _object: PlaceableObject | null; + + /** Has this object been deliberately destroyed as part of the deletion workflow? */ + protected _destroyed: boolean; + + constructor(data: object, context: DocumentConstructionContext); + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ + get object(): this["_object"]; + + /** A reference to the CanvasLayer which contains Document objects of this type. */ + get layer(): NonNullable["layer"] | null; + + /** An indicator for whether this document is currently rendered on the game canvas. */ + get rendered(): boolean; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + /** + * @see abstract.Document#_onCreate + */ + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onUpdate + */ + protected override _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onDelete + */ + protected _onDelete(options: DocumentModificationContext, userId: string): void; +} + +export interface CanvasBaseAmbientLight + extends ClientBaseAmbientLight { + // System note: in most but not all canvas documents + hidden?: boolean; +} + +declare class ClientBaseAmbientSound extends foundry.documents + .BaseAmbientSound { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +/** + * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be + * represented upon the game Canvas. + * @category - Mixins + */ +export class CanvasBaseAmbientSound extends ClientBaseAmbientSound { + /** A reference to the PlaceableObject instance which represents this Embedded Document. */ + _object: PlaceableObject | null; + + /** Has this object been deliberately destroyed as part of the deletion workflow? */ + protected _destroyed: boolean; + + constructor(data: object, context: DocumentConstructionContext); + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ + get object(): this["_object"]; + + /** A reference to the CanvasLayer which contains Document objects of this type. */ + get layer(): NonNullable["layer"] | null; + + /** An indicator for whether this document is currently rendered on the game canvas. */ + get rendered(): boolean; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + /** + * @see abstract.Document#_onCreate + */ + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onUpdate + */ + protected override _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onDelete + */ + protected _onDelete(options: DocumentModificationContext, userId: string): void; +} + +export interface CanvasBaseAmbientSound + extends ClientBaseAmbientSound { + // System note: in most but not all canvas documents + hidden?: boolean; +} + +export class ClientBaseActiveEffect | ClientBaseItem | null> extends foundry + .documents.BaseActiveEffect { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseActor | null> extends foundry.documents.BaseActor { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseAdventure extends foundry.documents.BaseAdventure { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseCards extends foundry.documents.BaseCards { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseChatMessage extends foundry.documents.BaseChatMessage { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseCombat extends foundry.documents.BaseCombat { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseCombatant extends foundry.documents + .BaseCombatant { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +declare class ClientBaseDrawing extends foundry.documents.BaseDrawing { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +/** + * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be + * represented upon the game Canvas. + * @category - Mixins + */ +export class CanvasBaseDrawing extends ClientBaseDrawing { + /** A reference to the PlaceableObject instance which represents this Embedded Document. */ + _object: PlaceableObject | null; + + /** Has this object been deliberately destroyed as part of the deletion workflow? */ + protected _destroyed: boolean; + + constructor(data: object, context: DocumentConstructionContext); + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ + get object(): this["_object"]; + + /** A reference to the CanvasLayer which contains Document objects of this type. */ + get layer(): NonNullable["layer"] | null; + + /** An indicator for whether this document is currently rendered on the game canvas. */ + get rendered(): boolean; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + /** + * @see abstract.Document#_onCreate + */ + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onUpdate + */ + protected override _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onDelete + */ + protected _onDelete(options: DocumentModificationContext, userId: string): void; +} + +export interface CanvasBaseDrawing extends ClientBaseDrawing { + // System note: in most but not all canvas documents + hidden?: boolean; +} + +export class ClientBaseFogExploration extends foundry.documents.BaseFogExploration { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): null; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseFolder extends foundry.documents.BaseFolder { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseItem | null> extends foundry.documents.BaseItem { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: SortingOptions & { updateData?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): { type: string }; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseJournalEntry extends foundry.documents.BaseJournalEntry { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseJournalEntryPage extends foundry.documents + .BaseJournalEntryPage { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseMacro extends foundry.documents.BaseMacro { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +declare class ClientBaseMeasuredTemplate extends foundry.documents + .BaseMeasuredTemplate { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +/** + * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be + * represented upon the game Canvas. + * @category - Mixins + */ +export class CanvasBaseMeasuredTemplate< + TParent extends ClientBaseScene | null +> extends ClientBaseMeasuredTemplate { + /** A reference to the PlaceableObject instance which represents this Embedded Document. */ + _object: PlaceableObject | null; + + /** Has this object been deliberately destroyed as part of the deletion workflow? */ + protected _destroyed: boolean; + + constructor(data: object, context: DocumentConstructionContext); + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ + get object(): this["_object"]; + + /** A reference to the CanvasLayer which contains Document objects of this type. */ + get layer(): NonNullable["layer"] | null; + + /** An indicator for whether this document is currently rendered on the game canvas. */ + get rendered(): boolean; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + /** + * @see abstract.Document#_onCreate + */ + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onUpdate + */ + protected override _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onDelete + */ + protected _onDelete(options: DocumentModificationContext, userId: string): void; +} + +export interface CanvasBaseMeasuredTemplate + extends ClientBaseMeasuredTemplate { + // System note: in most but not all canvas documents + hidden?: boolean; +} + +declare class ClientBaseNote extends foundry.documents.BaseNote { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +/** + * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be + * represented upon the game Canvas. + * @category - Mixins + */ +export class CanvasBaseNote extends ClientBaseNote { + /** A reference to the PlaceableObject instance which represents this Embedded Document. */ + _object: PlaceableObject | null; + + /** Has this object been deliberately destroyed as part of the deletion workflow? */ + protected _destroyed: boolean; + + constructor(data: object, context: DocumentConstructionContext); + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ + get object(): this["_object"]; + + /** A reference to the CanvasLayer which contains Document objects of this type. */ + get layer(): NonNullable["layer"] | null; + + /** An indicator for whether this document is currently rendered on the game canvas. */ + get rendered(): boolean; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + /** + * @see abstract.Document#_onCreate + */ + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onUpdate + */ + protected override _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onDelete + */ + protected _onDelete(options: DocumentModificationContext, userId: string): void; +} + +export interface CanvasBaseNote extends ClientBaseNote { + // System note: in most but not all canvas documents + hidden?: boolean; +} + +export class ClientBasePlaylist extends foundry.documents.BasePlaylist { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBasePlaylistSound extends foundry.documents + .BasePlaylistSound { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseRollTable extends foundry.documents.BaseRollTable { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseScene extends foundry.documents.BaseScene { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +export class ClientBaseTableResult extends foundry.documents + .BaseTableResult { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +declare class ClientBaseTile extends foundry.documents.BaseTile { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +/** + * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be + * represented upon the game Canvas. + * @category - Mixins + */ +export class CanvasBaseTile extends ClientBaseTile { + /** A reference to the PlaceableObject instance which represents this Embedded Document. */ + _object: PlaceableObject | null; + + /** Has this object been deliberately destroyed as part of the deletion workflow? */ + protected _destroyed: boolean; + + constructor(data: object, context: DocumentConstructionContext); + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ + get object(): this["_object"]; + + /** A reference to the CanvasLayer which contains Document objects of this type. */ + get layer(): NonNullable["layer"] | null; + + /** An indicator for whether this document is currently rendered on the game canvas. */ + get rendered(): boolean; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + /** + * @see abstract.Document#_onCreate + */ + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onUpdate + */ + protected override _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onDelete + */ + protected _onDelete(options: DocumentModificationContext, userId: string): void; +} + +export interface CanvasBaseTile extends ClientBaseTile { + // System note: in most but not all canvas documents + hidden?: boolean; +} + +declare class ClientBaseToken extends foundry.documents.BaseToken { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +/** + * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be + * represented upon the game Canvas. + * @category - Mixins + */ +export class CanvasBaseToken extends ClientBaseToken { + /** A reference to the PlaceableObject instance which represents this Embedded Document. */ + _object: PlaceableObject | null; + + /** Has this object been deliberately destroyed as part of the deletion workflow? */ + protected _destroyed: boolean; + + constructor(data: object, context: DocumentConstructionContext); + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ + get object(): this["_object"]; + + /** A reference to the CanvasLayer which contains Document objects of this type. */ + get layer(): NonNullable["layer"] | null; + + /** An indicator for whether this document is currently rendered on the game canvas. */ + get rendered(): boolean; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + /** + * @see abstract.Document#_onCreate + */ + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onUpdate + */ + protected override _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onDelete + */ + protected _onDelete(options: DocumentModificationContext, userId: string): void; +} + +export interface CanvasBaseToken extends ClientBaseToken { + // System note: in most but not all canvas documents + hidden?: boolean; +} + +export class ClientBaseUser extends foundry.documents.BaseUser { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +declare class ClientBaseWall extends foundry.documents.BaseWall { + protected _sheet: FormApplication | null; + + /** + * A collection of Application instances which should be re-rendered whenever this document is updated. + * The keys of this object are the application ids and the values are Application instances. Each + * Application in this object will have its render method called by {@link Document#render}. + * @see {@link Document#render} + */ + apps: { [K in number]?: Application }; + + constructor(data: object, context?: DocumentConstructionContext); + + static override name: string; + + protected override _initialize(options?: Record): void; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Return a reference to the parent Collection instance which contains this Document. */ + get collection(): Collection; + + /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ + get compendium(): CompendiumCollection | undefined; + + /** + * A boolean indicator for whether or not the current game User has ownership rights for this Document. + * Different Document types may have more specialized rules for what constitutes ownership. + */ + get isOwner(): boolean; + + /** Test whether this Document is owned by any non-Gamemaster User. */ + get hasPlayerOwner(): boolean; + + /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ + get limited(): boolean; + + /** Return a string which creates a dynamic link to this Document instance. */ + get link(): string; + + /** + * Return the permission level that the current game User has over this Document. + * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. + * + * @example Get the permission level the current user has for a document + * \`\`\`js + * game.user.id; // "dkasjkkj23kjf" + * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; + * actor.permission; // 2 + * \`\`\` + */ + get permission(): DocumentOwnershipLevel; + + /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ + get sheet(): FormApplication; + + /** A Universally Unique Identifier (uuid) for this Document instance. */ + get uuid(): DocumentUUID; + + /** + * A boolean indicator for whether the current game User has at least limited visibility for this Document. + * Different Document types may have more specialized rules for what determines visibility. + */ + get visible(): boolean; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** Obtain the FormApplication class constructor which should be used to configure this Document. */ + protected _getSheetClass(): Maybe; + + /** + * Prepare data for the Document. This method is called automatically by the DataModel#_initialize workflow. + * This method provides an opportunity for Document classes to define special data preparation logic. + * The work done by this method should be idempotent. There are situations in which prepareData may be called more + * than once. + */ + prepareData(): void; + + /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ + prepareBaseData(): void; + + /** + * Prepare all embedded Document instances which exist within this primary Document. + * @memberof ClientDocumentMixin# + */ + prepareEmbeddedDocuments(): void; + + /** + * Apply transformations or derivations to the values of the source data object. + * Compute data fields whose values are not stored to the database. + */ + prepareDerivedData(): void; + + /** + * Render all of the Application instances which are connected to this document by calling their respective + * @see Application#render + * @param [force=false] Force rendering + * @param [context={}] Optional context + */ + render(force?: boolean, context?: RenderOptions): void; + + /** + * Determine the sort order for this Document by positioning it relative a target sibling. + * See SortingHelper.performIntegerSort for more details + * @param [options] Sorting options provided to SortingHelper.performIntegerSort + * @param [options.updateData] Additional data changes which are applied to each sorted document + * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method + * @returns The Document after it has been re-sorted + */ + sortRelative({ updateData, ...sortOptions }: { updateData?: object; sortOptions?: object }): Promise; + + /** + * Construct a UUID relative to another document. + * @param doc The document to compare against. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getRelativeUUID(doc: foundry.abstract.Document): string; + + /** + * Handle clicking on a content link for this document. + * @param event The triggering click event. + */ + protected _onClickDocumentLink(event: MouseEvent): Promise; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + data: DeepPartial, + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _preCreateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are created. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of created Documents + * @param result An Array of created data objects + * @param options Options which modified the creation operation + * @param userId The ID of the User who triggered the operation + */ + protected _onCreateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _preUpdateEmbeddedDocuments( + embeddedName: string, + result: object[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of updated Documents + * @param result An Array of incremental data objects + * @param options Options which modified the update operation + * @param userId The ID of the User who triggered the operation + */ + protected _onUpdateEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: object, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _preDeleteEmbeddedDocuments( + embeddedName: string, + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. + * @param embeddedName The name of the embedded Document type + * @param documents An Array of deleted Documents + * @param result An Array of document IDs being deleted + * @param options Options which modified the deletion operation + * @param userId The ID of the User who triggered the operation + */ + protected _onDeleteEmbeddedDocuments( + embeddedName: string, + documents: foundry.abstract.Document[], + result: string[], + options: DocumentModificationContext, + userId: string + ): void; + + /** Gets the default new name for a Document */ + static defaultName(): string; + + /* -------------------------------------------- */ + /* Importing and Exporting */ + /* -------------------------------------------- */ + + /** + * Present a Dialog form to create a new Document of this type. + * Choose a name and a type from a select menu of types. + * @param [data] Initial data with which to populate the creation form + * @param [context={}] Additional context options or dialog positioning options + * @returns A Promise which resolves to the created Document, or null if the dialog was closed. + */ + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; + + /** + * Present a Dialog form to confirm deletion of this Document. + * @param [options] Positioning and sizing options for the resulting dialog + * @return A Promise which resolves to the deleted Document + */ + deleteDialog(options?: Record): Promise; + + /** + * Export document data to a JSON file which can be saved by the client and later imported into a different session. + * @param [options] Additional options passed to the {@link ClientDocumentMixin#toCompendium} method + */ + exportToJSON(options?: Record): void; + + /** + * Create a content link for this Document. + * @param [options] Additional options to configure how the link is constructed. + * @param [options.attrs] Attributes to set on the link. + * @param [options.dataset] Custom data- attributes to set on the link. + * @param [options.classes] Classes to add to the link. + * @param [options.name] A name to use for the Document, if different from the Document's name. + * @param [options.icon] A font-awesome icon class to use as the icon, if different to the Document's configured sidebarIcon. + */ + toAnchor(options?: { + attrs?: Record; + dataset?: Record; + classes?: string[]; + name?: string; + icon?: string; + }): HTMLAnchorElement; + + /** + * Serialize salient information about this Document when dragging it. + * @returns An object of drag data. + */ + toDragData(): object; + + /** + * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. + * The dropped data could have: + * 1. A data object explicitly provided + * 2. A UUID + * + * @param data The data object extracted from a DataTransfer event + * @param options Additional options which affect drop data behavior + * @returns The resolved Document + * @throws If a Document could not be retrieved from the provided data. + */ + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; + + /** + * Update this Document using a provided JSON string. + * @param json Raw JSON data to import + * @returns The updated Document instance + */ + importFromJSON(json: string): Promise; + + /** Render an import dialog for updating the data related to this Document through an exported JSON file */ + importFromJSONDialog(): Promise; + + /** + * Transform the Document data to be stored in a Compendium pack. + * Remove any features of the data which are world-specific. + * @param [pack] A specific pack being exported to + * @param [options] Additional options which modify how the document is converted + * @param [options.clearFlags=false] Clear the flags object + * @param [options.clearSort=true] Clear the currently assigned folder and sort order + * @param [options.clearOwnership=true] Clear document ownership + * @param [options.clearState=true] Clear fields which store document state + * @param [options.keepId=false] Retain the current Document id + * @returns A data object of cleaned data suitable for compendium import + */ + toCompendium( + pack?: CompendiumCollection, + options?: { + clearSort?: boolean; + clearFlags?: boolean; + clearOwnership?: boolean; + clearState?: boolean; + keepId?: boolean; + } + ): this["_source"]; +} + +/** + * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be + * represented upon the game Canvas. + * @category - Mixins + */ +export class CanvasBaseWall extends ClientBaseWall { + /** A reference to the PlaceableObject instance which represents this Embedded Document. */ + _object: PlaceableObject | null; + + /** Has this object been deliberately destroyed as part of the deletion workflow? */ + protected _destroyed: boolean; + + constructor(data: object, context: DocumentConstructionContext); + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ + get object(): this["_object"]; + + /** A reference to the CanvasLayer which contains Document objects of this type. */ + get layer(): NonNullable["layer"] | null; + + /** An indicator for whether this document is currently rendered on the game canvas. */ + get rendered(): boolean; + + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + /** + * @see abstract.Document#_onCreate + */ + protected override _onCreate( + data: this["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onUpdate + */ + protected override _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onDelete + */ + protected _onDelete(options: DocumentModificationContext, userId: string): void; +} + +export interface CanvasBaseWall extends ClientBaseWall { + // System note: in most but not all canvas documents + hidden?: boolean; +} diff --git a/types/foundry/client/documents/client-document.ts b/types/foundry/client/documents/client-document.ts new file mode 100644 index 00000000000..7fa3dd22ff2 --- /dev/null +++ b/types/foundry/client/documents/client-document.ts @@ -0,0 +1,16 @@ +import { ClientBaseScene } from "./client-base-mixes.mjs"; + +declare global { + // Interfaces for ClientDocuments, given there is no common base with the generated intermediate classes + interface ClientDocument extends foundry.abstract.Document { + get hasPlayerOwner(): boolean; + get isOwner(): boolean; + get sheet(): FormApplication; + get uuid(): DocumentUUID; + } + + interface CanvasDocument extends ClientDocument { + readonly parent: ClientBaseScene | null; + hidden?: boolean; + } +} diff --git a/types/foundry/client/documents/combat.d.ts b/types/foundry/client/documents/combat.d.ts index 001731edea2..a0dc734ae8b 100644 --- a/types/foundry/client/documents/combat.d.ts +++ b/types/foundry/client/documents/combat.d.ts @@ -1,4 +1,4 @@ -import { CombatConstructor } from "./constructors"; +import { ClientBaseCombat } from "./client-base-mixes.mjs"; declare global { /** @@ -6,13 +6,13 @@ declare global { * Each Combat document contains CombatData which defines its data schema. * @param [data={}] Initial data provided to construct the Combat document */ - class Combat extends CombatConstructor { - constructor(data: PreCreate, context?: DocumentConstructionContext); + class Combat extends ClientBaseCombat { + constructor(data: PreCreate, context?: DocumentConstructionContext); active: boolean; /** Track the sorted turn order of this combat encounter */ - turns: Combatant[]; + turns: CollectionValue[]; /** Record the current round, turn, and tokenId to understand changes in the encounter state */ current: { @@ -38,13 +38,13 @@ declare global { /* -------------------------------------------- */ /** Get the Combatant who has the current turn. */ - get combatant(): Combatant | undefined; + get combatant(): CollectionValue | undefined; /** The numeric round of the Combat encounter */ get round(): number; /** A reference to the Scene document within which this Combat encounter occurs */ - get scene(): Scene | undefined; + get scene(): NonNullable["actor"]>["parent"]; /** Return the object of settings which modify the Combat Tracker behavior */ get settings(): Record; @@ -158,54 +158,45 @@ declare global { protected override _onCreate( data: this["_source"], - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; - protected override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; protected override _onCreateEmbeddedDocuments( type: "Combatant", - documents: Combatant[], - result: Combatant["_source"][], - options: DocumentModificationContext, + documents: Combatant[], + result: Combatant["_source"][], + options: DocumentModificationContext, userId: string ): void; protected override _onUpdateEmbeddedDocuments( embeddedName: "Combatant", - documents: Combatant[], - result: Combatant["_source"][], - options: DocumentModificationContext, + documents: Combatant[], + result: Combatant["_source"][], + options: DocumentModificationContext, userId: string ): void; protected override _onDeleteEmbeddedDocuments( embeddedName: "Combatant", - documents: Combatant[], - result: Combatant["_source"][], - options: DocumentModificationContext, + documents: Combatant[], + result: string[], + options: DocumentModificationContext, userId: string ): void; } - interface Combat { - readonly data: foundry.data.CombatData; - - // V10 shim - readonly flags: this["data"]["flags"]; - - createEmbeddedDocuments( - embeddedName: "Combatant", - data: PreCreate[], - context?: DocumentModificationContext - ): Promise[]>; + interface Combat extends ClientBaseCombat { + readonly combatants: foundry.abstract.EmbeddedCollection>; } interface RollInitiativeOptions { diff --git a/types/foundry/client/documents/combatant.d.ts b/types/foundry/client/documents/combatant.d.ts index 640c63b217c..fe50b8dc156 100644 --- a/types/foundry/client/documents/combatant.d.ts +++ b/types/foundry/client/documents/combatant.d.ts @@ -1,25 +1,17 @@ -import { CombatantConstructor } from "./constructors"; +import { ClientBaseCombatant } from "./client-base-mixes.mjs"; declare global { /** - * The Combatant embedded document within a Combat document which extends the BaseRollTable abstraction. - * Each Combatant belongs to the effects collection of its parent Document. - * Each Combatant contains a CombatantData object which provides its source data. + * The client-side Combatant document which extends the common BaseCombatant model. * - * @see {@link data.CombatantData} The Combatant data schema - * @see {@link documents.Combat} The Combat document which contains Combatant embedded documents + * @see {@link Combat} The Combat document which contains Combatant embedded documents + * @see {@link CombatantConfig} The application which configures a Combatant. */ class Combatant< - TParent extends Combat | null = Combat | null, - TActor extends Actor | null = Actor | null - > extends CombatantConstructor { - constructor(data: PreCreate, context?: DocumentConstructionContext); - - /** A cached reference to the Token which this Combatant represents, if any */ - protected _token: NonNullable["parent"]; - - /** A cached reference to the Actor which this Combatant represents, if any */ - protected _actor: TActor; + TParent extends Combat | null, + TTokenDocument extends TokenDocument | null = TokenDocument | null + > extends ClientBaseCombatant { + constructor(data: PreCreate, context?: DocumentConstructionContext); /** The current value of the special tracked resource which pertains to this Combatant */ resource: { value: number } | null; @@ -46,10 +38,10 @@ declare global { get isVisible(): boolean; /** A reference to the Actor document which this Combatant represents, if any */ - get actor(): TActor; + get actor(): NonNullable["actor"]; /** A reference to the Token document which this Combatant represents, if any */ - get token(): NonNullable["parent"]; + get token(): TTokenDocument; /** An array of User documents who have ownership of this Document */ get players(): User[]; @@ -62,7 +54,7 @@ declare global { /* -------------------------------------------- */ override testUserPermission( - user: foundry.documents.BaseUser, + user: User, permission: DocumentOwnershipString | DocumentOwnershipLevel, { exact }?: { exact?: boolean } ): boolean; @@ -94,11 +86,10 @@ declare global { _getInitiativeFormula(): string; } - interface Combatant { - readonly data: foundry.data.CombatantData; - - readonly parent: TParent; - + interface Combatant< + TParent extends Combat | null, + TTokenDocument extends TokenDocument | null = TokenDocument | null + > extends ClientBaseCombatant { _sheet: CombatantConfig; } } diff --git a/types/foundry/client/documents/constructors.d.ts b/types/foundry/client/documents/constructors.d.ts deleted file mode 100644 index c77ce8ae914..00000000000 --- a/types/foundry/client/documents/constructors.d.ts +++ /dev/null @@ -1,56 +0,0 @@ -export const AmbientLightDocumentConstructor: CanvasDocumentMixin< - typeof foundry.documents.BaseAmbientLight, - LightingLayer ->; - -export const AmbientSoundDocumentConstructor: CanvasDocumentMixin< - typeof foundry.documents.BaseAmbientSound, - SoundsLayer ->; - -export const ActiveEffectConstructor: ClientDocumentMixin; - -export const ActorConstructor: ClientDocumentMixin; - -export const CardsConstructor: ClientDocumentMixin; - -export const CombatantConstructor: ClientDocumentMixin; - -export const CombatConstructor: ClientDocumentMixin; - -export const ChatMessageConstructor: ClientDocumentMixin; - -export const DrawingConstructor: CanvasDocumentMixin; - -export const FogExplorationConstructor: ClientDocumentMixin; - -export const FolderConstructor: ClientDocumentMixin; - -export const ItemConstructor: ClientDocumentMixin; - -export const MacroConstructor: ClientDocumentMixin; - -export const MeasuredTemplateDocumentConstructor: CanvasDocumentMixin< - typeof foundry.documents.BaseMeasuredTemplate, - TemplateLayer ->; - -export const PlaylistConstructor: ClientDocumentMixin; - -export const PlaylistSoundConstructor: ClientDocumentMixin; - -export const RollTableConstructor: ClientDocumentMixin; - -export const NoteDocumentConstructor: CanvasDocumentMixin; - -export const SceneConstructor: ClientDocumentMixin; - -export const TableResultConstructor: ClientDocumentMixin; - -export const TileDocumentConstructor: CanvasDocumentMixin; - -export const TokenDocumentConstructor: CanvasDocumentMixin>; - -export const WallDocumentConstructor: CanvasDocumentMixin; - -export const UserConstructor: ClientDocumentMixin; diff --git a/types/foundry/client/documents/drawing-document.d.ts b/types/foundry/client/documents/drawing-document.d.ts index 6faf11feef8..7c4b40bbe2d 100644 --- a/types/foundry/client/documents/drawing-document.d.ts +++ b/types/foundry/client/documents/drawing-document.d.ts @@ -1,4 +1,4 @@ -import { DrawingConstructor } from "./constructors"; +import { CanvasBaseDrawing } from "./client-base-mixes.mjs"; declare global { /** @@ -9,7 +9,7 @@ declare global { * @see {@link applications.DrawingConfig} The Drawing configuration application * */ - class DrawingDocument extends DrawingConstructor { + class DrawingDocument extends CanvasBaseDrawing { /** A reference to the User who created the Drawing document. */ get author(): User | undefined; @@ -17,9 +17,7 @@ declare global { override get isOwner(): boolean; } - interface DrawingDocument { - readonly parent: Scene | null; - - readonly _object: Drawing; + interface DrawingDocument extends CanvasBaseDrawing { + readonly _object: Drawing | null; } } diff --git a/types/foundry/client/documents/fog-exploration.d.ts b/types/foundry/client/documents/fog-exploration.d.ts index fad0ac7b2df..15d54e72fce 100644 --- a/types/foundry/client/documents/fog-exploration.d.ts +++ b/types/foundry/client/documents/fog-exploration.d.ts @@ -1,15 +1,15 @@ -import { FogExplorationConstructor } from "./constructors"; import * as io from "socket.io"; +import { ClientBaseFogExploration } from "./client-base-mixes.mjs"; declare global { /** * The client-side FogExploration document which extends the common BaseFogExploration abstraction. * Each FogExploration document contains FogExplorationData which defines its data schema. */ - class FogExploration extends FogExplorationConstructor { + class FogExploration extends ClientBaseFogExploration { constructor( - data?: PreCreate, - context?: DocumentConstructionContext + data?: PreCreate, + context?: DocumentConstructionContext ); /** @@ -18,7 +18,7 @@ declare global { * @param [force=false] Force the position to be re-explored * @returns Is the source position newly explored? */ - explore(source: PointSource, force?: boolean): boolean; + explore(source: PointSource>, force?: boolean): boolean; /** Obtain the fog of war exploration progress for a specific Scene and User. */ static get( diff --git a/types/foundry/client/documents/folder.d.ts b/types/foundry/client/documents/folder.d.ts index 2dcf1ee4f73..c6d60814d2b 100644 --- a/types/foundry/client/documents/folder.d.ts +++ b/types/foundry/client/documents/folder.d.ts @@ -1,27 +1,27 @@ -import { FolderConstructor } from "./constructors"; +import { ClientBaseFolder } from "./client-base-mixes.mjs"; declare global { /** - * The client-side Folder document which extends the common BaseFolder abstraction. - * Each Folder document contains FolderData which defines its data schema. - * @see {@link data.FolderData} The Folder data schema - * @see {@link documents.Folders} The world-level collection of Folder documents - * @see {@link embedded.FolderSound} The FolderSound embedded document within a parent Folder - * @see {@link applications.FolderConfig} The Folder configuration application + * The client-side Folder document which extends the common BaseFolder model. * - ent - */ - class Folder extends FolderConstructor { + * @see {@link Folders} The world-level collection of Folder documents + * @see {@link FolderConfig} The Folder configuration application + */ + class Folder extends ClientBaseFolder { /** * Create a new Folder by rendering a dialog window to provide basic creation details * @param data Initial data with which to populate the creation form * @param options Initial positioning and sizing options for the dialog form * @return An active FolderConfig instance for creating the new Folder entity */ - static override createDialog( - data?: { folder?: string }, - options?: FormApplicationOptions - ): Promise; + static createDialog( + this: ConstructorOf, + data?: Record, + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; /** The depth of this folder in its sidebar tree */ depth: number; @@ -74,8 +74,8 @@ declare global { */ getSubfolders(recursive?: boolean): this[]; - protected override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; } - type EnfolderableDocument = Actor | Item | Macro | Scene | JournalEntry | RollTable; + type EnfolderableDocument = Actor | Item | Macro | Scene | JournalEntry | RollTable; } diff --git a/types/foundry/client/documents/index.d.ts b/types/foundry/client/documents/index.d.ts index 54d95e94440..464ad26aaf0 100644 --- a/types/foundry/client/documents/index.d.ts +++ b/types/foundry/client/documents/index.d.ts @@ -4,6 +4,7 @@ import "./ambient-light-document"; import "./ambient-sound-document"; import "./cards"; import "./chat-message"; +import "./client-document"; import "./combat"; import "./combatant"; import "./drawing-document"; @@ -14,7 +15,6 @@ import "./journal-entry"; import "./journal-entry-page"; import "./macro"; import "./measured-template-document"; -import "./mixins"; import "./note-document"; import "./playlist"; import "./playlist-sound"; @@ -26,15 +26,16 @@ import "./tile-document"; import "./token-document"; import "./user"; import "./wall-document"; +import "./client-base-mixes.mjs"; declare global { type WorldDocument = - | Actor + | Actor | Cards | ChatMessage | Combat | Folder - | Item + | Item | JournalEntry | Macro | Playlist diff --git a/types/foundry/client/documents/item.d.ts b/types/foundry/client/documents/item.d.ts index 905d709516b..1805dc2596a 100644 --- a/types/foundry/client/documents/item.d.ts +++ b/types/foundry/client/documents/item.d.ts @@ -1,4 +1,4 @@ -import { ItemConstructor } from "./constructors"; +import { ClientBaseItem } from "./client-base-mixes.mjs"; declare global { /** @@ -8,9 +8,9 @@ declare global { * @see {@link documents.Items} The world-level collection of Item documents * @see {@link applications.ItemSheet} The Item configuration application */ - class Item extends ItemConstructor { + class Item | null> | null> extends ClientBaseItem { /** A convenience alias of Item#parent which is more semantically intuitive */ - get actor(): this["parent"]; + get actor(): TParent; img: ImageFilePath; @@ -31,24 +31,20 @@ declare global { protected override _getSheetClass(): ConstructorOf>; - protected static override _onCreateDocuments( - this: ConstructorOf, - items: T[], - context: DocumentModificationContext + protected static override _onCreateDocuments( + this: ConstructorOf, + items: TDocument[], + context: DocumentModificationContext ): void; - protected static override _onDeleteDocuments( - this: ConstructorOf, - items: T[], - context: DocumentModificationContext + protected static override _onDeleteDocuments( + this: ConstructorOf, + items: TDocument[], + context: DocumentModificationContext ): void; } - interface Item { - readonly parent: TParent | null; - - get collection(): Items; - + interface Item | null> | null> extends ClientBaseItem { get uuid(): ItemUUID; _sheet: ItemSheet | null; @@ -57,5 +53,5 @@ declare global { } type EmbeddedItemUUID = `Actor.${string}.Item.${string}`; - type ItemUUID = WorldDocumentUUID | EmbeddedItemUUID | CompendiumUUID; + type ItemUUID = WorldDocumentUUID> | EmbeddedItemUUID | CompendiumUUID; } diff --git a/types/foundry/client/documents/journal-entry-page.d.ts b/types/foundry/client/documents/journal-entry-page.d.ts index e634ead505d..ee0011c061e 100644 --- a/types/foundry/client/documents/journal-entry-page.d.ts +++ b/types/foundry/client/documents/journal-entry-page.d.ts @@ -1,4 +1,4 @@ -export {}; +import { ClientBaseJournalEntryPage } from "./client-base-mixes.mjs"; declare global { /** @@ -6,7 +6,7 @@ declare global { * * @see {@link JournalEntry} The JournalEntry document type which contains JournalEntryPage embedded documents. */ - class JournalEntryPage extends ClientDocument2 { + class JournalEntryPage extends ClientBaseJournalEntryPage { /** The table of contents for this JournalEntryPage. */ get toc(): JournalEntryPageHeading; @@ -61,17 +61,14 @@ declare global { protected override _onUpdate( data: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; } - interface JournalEntryPage - extends BaseDocumentWithOmissions>, - ClientDocument2 { - readonly _source: foundry.documents.JournalEntryPageSource; - + interface JournalEntryPage extends ClientBaseJournalEntryPage { get documentName(): "JournalEntryPage"; + get sheet(): JournalPageSheet; } interface JournalEntryPageHeading { diff --git a/types/foundry/client/documents/journal-entry.d.ts b/types/foundry/client/documents/journal-entry.d.ts index e56f5acb202..47313dd3466 100644 --- a/types/foundry/client/documents/journal-entry.d.ts +++ b/types/foundry/client/documents/journal-entry.d.ts @@ -1,4 +1,4 @@ -export {}; +import { ClientBaseJournalEntry } from "./client-base-mixes.mjs"; declare global { /** @@ -7,7 +7,7 @@ declare global { * @see {@link Journal} The world-level collection of JournalEntry documents * @see {@link JournalSheet} The JournalEntry configuration application */ - class JournalEntry extends ClientDocument2 { + class JournalEntry extends ClientBaseJournalEntry { /* -------------------------------------------- */ /* Properties */ /* -------------------------------------------- */ @@ -52,20 +52,16 @@ declare global { protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentUpdateContext, userId: string ): void; - protected override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; } - interface JournalEntry - extends BaseDocumentWithOmissions, - ClientDocument2 { - readonly _source: foundry.documents.JournalEntrySource; + interface JournalEntry extends ClientBaseJournalEntry { readonly pages: foundry.abstract.EmbeddedCollection>; - get documentName(): "JournalEntry"; get sheet(): JournalSheet; } } diff --git a/types/foundry/client/documents/macro.d.ts b/types/foundry/client/documents/macro.d.ts index 0d2574bda2d..8e9d615e643 100644 --- a/types/foundry/client/documents/macro.d.ts +++ b/types/foundry/client/documents/macro.d.ts @@ -1,16 +1,15 @@ -import { MacroConstructor } from "./constructors"; +import { ClientBaseMacro } from "./client-base-mixes.mjs"; declare global { /** - * The client-side Macro document which extends the common BaseMacro abstraction. - * Each Macro document contains MacroData which defines its data schema. + * The client-side Folder document which extends the common BaseFolder model. * - * @see {@link data.MacroData} The Macro data schema - * @see {@link documents.Macros} The world-level collection of Macro documents - * @see {@link applications.MacroConfig} The Macro configuration application + * @see {@link Folders} The world-level collection of Folder documents + * @see {@link FolderConfig} The Folder configuration application */ - class Macro extends MacroConstructor { + class Macro extends ClientBaseMacro { command: string; + /* -------------------------------------------- */ /* Properties */ /* -------------------------------------------- */ @@ -28,18 +27,30 @@ declare global { * @param [scope.actor] An Actor who is the protagonist of the executed action * @param [scope.token] A Token which is the protagonist of the executed action */ - execute({ actor, token }?: { actor?: Actor; token?: Token }): void; + execute({ actor, token }?: { actor?: Actor | null>; token?: Token }): void; /** * Execute the command as a chat macro. * Chat macros simulate the process of the command being entered into the Chat Log input textarea. */ - protected _executeChat({ actor, token }?: { actor?: Actor; token?: Token }): void; + protected _executeChat({ + actor, + token, + }?: { + actor?: Actor | null>; + token?: Token; + }): void; /** * Execute the command as a script macro. * Script Macros are wrapped in an async IIFE to allow the use of asynchronous commands and await statements. */ - protected _executeScript({ actor, token }?: { actor?: Actor; token?: Token }): void; + protected _executeScript({ + actor, + token, + }?: { + actor?: Actor | null>; + token?: Token; + }): void; } } diff --git a/types/foundry/client/documents/measured-template-document.d.ts b/types/foundry/client/documents/measured-template-document.d.ts index d2a9ae29882..fdb90c49031 100644 --- a/types/foundry/client/documents/measured-template-document.d.ts +++ b/types/foundry/client/documents/measured-template-document.d.ts @@ -1,27 +1,26 @@ -import { MeasuredTemplateDocumentConstructor } from "./constructors"; +import { CanvasBaseMeasuredTemplate } from "./client-base-mixes.mjs"; declare global { /** - * The client-side MeasuredTemplate embedded document which extends the common BaseMeasuredTemplate abstraction. - * Each MeasuredTemplate document contains MeasuredTemplateData which defines its data schema. + * The client-side MeasuredTemplate document which extends the common BaseMeasuredTemplate document model. + * + * @see {@link Scene} The Scene document type which contains MeasuredTemplate documents + * @see {@link MeasuredTemplateConfig} The MeasuredTemplate configuration application */ - class MeasuredTemplateDocument extends MeasuredTemplateDocumentConstructor { + class MeasuredTemplateDocument extends CanvasBaseMeasuredTemplate { /* -------------------------------------------- */ - /* Properties */ + /* Model Properties */ /* -------------------------------------------- */ - /** A flag for whether the current User has full ownership over the MeasuredTemplate document. */ - override get isOwner(): boolean; - } - - interface MeasuredTemplateDocument { - readonly parent: Scene | null; - - _sheet: MeasuredTemplateConfig | null; - /** A reference to the User who created the MeasuredTemplate document. */ - readonly author: User | undefined; + get author(): User; + + /** Rotation is an alias for direction */ + get rotation(): number; + } - readonly _object: MeasuredTemplate | null; + interface MeasuredTemplateDocument extends CanvasBaseMeasuredTemplate { + _sheet: MeasuredTemplateConfig | null; + _object: MeasuredTemplate | null; } } diff --git a/types/foundry/client/documents/mixins/canvas-document-mixin.d.ts b/types/foundry/client/documents/mixins/canvas-document-mixin.d.ts deleted file mode 100644 index 6849fcdacee..00000000000 --- a/types/foundry/client/documents/mixins/canvas-document-mixin.d.ts +++ /dev/null @@ -1,61 +0,0 @@ -export {}; - -declare global { - /** - * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be - * represented upon the game Canvas. - * @mixin - */ - function CanvasDocumentMixin( - Base: TDocument - ): CanvasDocumentMixin; - - type CanvasDocumentMixin< - TDocument extends typeof foundry.abstract.Document, - TLayer extends PlaceablesLayer - > = TDocument & { - new (...args: any[]): CanvasDocument, TLayer> & InstanceType; - }; - - class CanvasDocument< - TDocument extends foundry.abstract.Document = foundry.abstract.Document, - TLayer extends PlaceablesLayer = PlaceablesLayer - > extends ClientDocument { - constructor(data: PreCreate, context?: DocumentModificationContext); - - /** A reference to the PlaceableObject instance which represents this Embedded Document. */ - protected _object: TLayer["placeables"][number] | null; - - /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ - get object(): TLayer["placeables"][number]; - - /** A reference to the CanvasLayer which contains Document objects of this type. */ - get layer(): TLayer; - - /** An indicator for whether this document is currently rendered on the game canvas. */ - get rendered(): boolean; - - protected override _onCreate( - data: this["_source"], - options: DocumentModificationContext, - userId: string - ): void; - - protected override _onUpdate( - changed: DeepPartial, - options: DocumentModificationContext, - userId: string - ): void; - - protected override _onDelete(options: DocumentModificationContext, userId: string): void; - } - - interface CanvasDocument< - TDocument extends foundry.abstract.Document = foundry.abstract.Document, - TLayer extends PlaceablesLayer = PlaceablesLayer - > extends ClientDocument { - x: number; - y: number; - hidden: boolean; - } -} diff --git a/types/foundry/client/documents/mixins/canvas-document-mixin2.d.ts b/types/foundry/client/documents/mixins/canvas-document-mixin2.d.ts deleted file mode 100644 index b420062a296..00000000000 --- a/types/foundry/client/documents/mixins/canvas-document-mixin2.d.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be - * represented upon the game Canvas. - * @category - Mixins - */ -declare class CanvasDocument2< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TParent extends ClientDocument2 | null = ClientDocument2 | null -> extends ClientDocument2 { - /** A reference to the PlaceableObject instance which represents this Embedded Document. */ - _object: PlaceableObject | null; - - /** Has this object been deliberately destroyed as part of the deletion workflow? */ - protected _destroyed: boolean; - - constructor(data: object, context: DocumentConstructionContext); - - /* -------------------------------------------- */ - /* Properties */ - /* -------------------------------------------- */ - - /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ - get object(): this["_object"]; - - /** A reference to the CanvasLayer which contains Document objects of this type. */ - get layer(): NonNullable["layer"] | null; - - /** An indicator for whether this document is currently rendered on the game canvas. */ - get rendered(): boolean; - - /* -------------------------------------------- */ - /* Event Handlers */ - /* -------------------------------------------- */ - - /** - * @see abstract.Document#_onCreate - */ - protected _onCreate(data: this["_source"], options: DocumentModificationContext, userId: string): void; - - /** - * @see abstract.Document#_onUpdate - */ - protected _onUpdate( - changed: DeepPartial, - options: DocumentUpdateContext, - userId: string - ): void; - - /** - * @see abstract.Document#_onDelete - */ - protected _onDelete(options: DocumentModificationContext, userId: string): void; -} - -declare interface CanvasDocument2< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TParent extends ClientDocument2 | null = ClientDocument2 | null -> extends ClientDocument2 { - // System note: in most but not all canvas documents - hidden?: boolean; -} diff --git a/types/foundry/client/documents/mixins/client-document-mixin.d.ts b/types/foundry/client/documents/mixins/client-document-mixin.d.ts deleted file mode 100644 index ed3268e0715..00000000000 --- a/types/foundry/client/documents/mixins/client-document-mixin.d.ts +++ /dev/null @@ -1,317 +0,0 @@ -/** - * The client-side document mixin which is used to extend the common BaseDocument. - * This mixin provides the client-side interface for database operations and common document behaviors. - * @mixin - */ -declare function ClientDocumentMixin(Base: T): ClientDocumentMixin; - -declare type ClientDocumentMixin = { - new (...args: any[]): ClientDocument> & InstanceType; - - /** - * Present a Dialog form to create a new Document of this type. - * Choose a name and a type from a select menu of types. - * @param data Initial data with which to populate the creation form - * @param [options] Positioning and sizing options for the resulting dialog - * @return A Promise which resolves to the created Document - */ - createDialog( - data?: { folder?: string }, - options?: Partial - ): Promise> | undefined>; - - /** - * A helper function to handle obtaining the relevant Document from dropped data provided via a DataTransfer event. - * The dropped data could have: - * 1. A compendium pack and entry id - * 2. A World Entity _id - * 3. A data object explicitly provided - * - * @param data The data object extracted from a DataTransfer event - * @param [options={}] Additional options which configure data retrieval - * @param [options.importWorld=false] Import the provided document data into the World, if it is not already a - * World-level Document reference - * @return The Document data that should be handled by the drop handler - */ - fromDropData( - this: ConstructorOf, - data: DropCanvasData, - { importWorld }?: { importWorld?: boolean } - ): Promise; -} & T; - -declare class ClientDocument extends foundry - .abstract.Document { - /** - * A collection of Application instances which should be re-rendered whenever this document is updated. - * The keys of this object are the application ids and the values are Application instances. Each - * Application in this object will have its render method called by {@link Document#render}. - * @see {@link Document#render} - */ - apps: Record; - - /** A cached reference to the FormApplication instance used to configure this Document. */ - protected _sheet: FormApplication | null; - - protected override _initialize(): void; - - /* -------------------------------------------- */ - /* Properties */ - /* -------------------------------------------- */ - - /** Return a reference to the parent Collection instance which contains this Document. */ - get collection(): Collection; - - /** A reference to the Compendium Collection which contains this Document, if any, otherwise undefined. */ - get compendium(): CompendiumCollection | undefined; - - /** - * Return a reference to the Folder to which this Document belongs, if any. - * - * @example A Document may belong to a Folder - * let folder = game.folders.entities[0]; - * let actor = await Actor.create({name: "New Actor", folder: folder.id}); - * console.log(actor.data.folder); // folder.id; - * console.log(actor.folder); // folder; - */ - get folder(): Folder | null; - - /** - * A boolean indicator for whether or not the current game User has ownership rights for this Document. - * Different Document types may have more specialized rules for what constitutes ownership. - */ - get isOwner(): boolean; - - /** Test whether this Document is owned by any non-Gamemaster User. */ - get hasPlayerOwner(): boolean; - - /** A boolean indicator for whether the current game User has exactly LIMITED visibility (and no greater). */ - get limited(): boolean; - - /** Return a string which creates a dynamic link to this Document instance. */ - get link(): string; - - /** - * Return the permission level that the current game User has over this Document. - * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. - * - * @example Get the permission level the current user has for a document - * ```js - * game.user.id; // "dkasjkkj23kjf" - * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; - * actor.permission; // 2 - * ``` - */ - get permission(): DocumentOwnershipLevel; - - /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ - get sheet(): FormApplication | null; - - /** A Universally Unique Identifier (uuid) for this Document instance. */ - get uuid(): DocumentUUID; - - /** - * A boolean indicator for whether or not the current game User has at least limited visibility for this Document. - * Different Document types may have more specialized rules for what determines visibility. - */ - get visible(): boolean; - - /* -------------------------------------------- */ - /* Methods */ - /* -------------------------------------------- */ - - /** Obtain the FormApplication class constructor which should be used to configure this Document. */ - protected _getSheetClass(): ConstructorOf; - - /** - * Prepare data for the Document. - * Begin by resetting the prepared data back to its source state. - * Next prepare any embedded Documents and compute any derived data elements. - */ - prepareData(): void; - - /** Prepare data related to this Document itself, before any embedded Documents or derived data is computed. */ - prepareBaseData(): void; - - /** Prepare all embedded Document instances which exist within this primary Document. */ - prepareEmbeddedDocuments(): void; - - /** - * Apply transformations or derivations to the values of the source data object. - * Compute data fields whose values are not stored to the database. - */ - prepareDerivedData(): void; - - /** - * Render all of the Application instances which are connected to this document by calling their respective - * @see Application#render - * @param [force=false] Force rendering - * @param [context={}] Optional context - */ - render(force?: boolean, context?: RenderOptions): void; - - /** - * Determine the sort order for this Document by positioning it relative a target sibling. - * See SortingHelper.performIntegerSort for more details - * @param [options] Sorting options provided to SortingHelper.performIntegerSort - * @param [updateData] Additional data changes which are applied to each sorted document - * @param [sortOptions] Options which are passed to the SortingHelpers.performIntegerSort method - * @returns The Document after it has been re-sorted - */ - sortRelative({ - target, - siblings, - sortKey, - sortBefore, - updateData, - }: { - target?: TObject; - siblings?: TObject[]; - sortKey?: keyof TObject; - sortBefore?: boolean; - updateData?: object; - }): Promise; - - /* -------------------------------------------- */ - /* Event Handlers */ - /* -------------------------------------------- */ - - protected override _onCreate( - data: this["_source"], - options: DocumentModificationContext, - userId: string - ): void; - - protected override _onUpdate( - changed: DeepPartial, - options: DocumentModificationContext, - userId: string - ): void; - - protected override _onDelete(options: DocumentModificationContext, userId: string): void; - - /** - * Preliminary actions taken before a set of embedded Documents in this parent Document are created. - * @param embeddedName The name of the embedded Document type - * @param result An Array of created data objects - * @param options Options which modified the creation operation - * @param userId The ID of the User who triggered the operation - */ - protected _preCreateEmbeddedDocuments( - embeddedName: string, - result: ClientDocument["_source"][], - options: DocumentModificationContext, - userId: string - ): void; - - /** - * Follow-up actions taken after a set of embedded Documents in this parent Document are created. - * @param embeddedName The name of the embedded Document type - * @param documents An Array of created Documents - * @param result An Array of created data objects - * @param options Options which modified the creation operation - * @param userId The ID of the User who triggered the operation - */ - protected _onCreateEmbeddedDocuments( - embeddedName: string, - documents: ClientDocument[], - result: ClientDocument["_source"][], - options: DocumentModificationContext, - userId: string - ): void; - - /** - * Preliminary actions taken before a set of embedded Documents in this parent Document are updated. - * @param embeddedName The name of the embedded Document type - * @param result An Array of incremental data objects - * @param options Options which modified the update operation - * @param userId The ID of the User who triggered the operation - */ - protected _preUpdateEmbeddedDocuments( - embeddedName: string, - result: ClientDocument["_source"][], - options: DocumentModificationContext, - userId: string - ): void; - - /** - * Follow-up actions taken after a set of embedded Documents in this parent Document are updated. - * @param embeddedName The name of the embedded Document type - * @param documents An Array of updated Documents - * @param result An Array of incremental data objects - * @param options Options which modified the update operation - * @param userId The ID of the User who triggered the operation - */ - protected _onUpdateEmbeddedDocuments( - embeddedName: string, - documents: ClientDocument[], - result: ClientDocument["_source"][], - options: DocumentModificationContext, - userId: string - ): void; - - /** - * Preliminary actions taken before a set of embedded Documents in this parent Document are deleted. - * @param embeddedName The name of the embedded Document type - * @param result An Array of document IDs being deleted - * @param options Options which modified the deletion operation - * @param userId The ID of the User who triggered the operation - */ - protected _preDeleteEmbeddedDocuments( - embeddedName: string, - result: ClientDocument["_source"][], - options: DocumentModificationContext, - userId: string - ): void; - - /** - * Follow-up actions taken after a set of embedded Documents in this parent Document are deleted. - * @param embeddedName The name of the embedded Document type - * @param documents An Array of deleted Documents - * @param result An Array of document IDs being deleted - * @param options Options which modified the deletion operation - * @param userId The ID of the User who triggered the operation - */ - protected _onDeleteEmbeddedDocuments( - embeddedName: string, - documents: ClientDocument[], - result: ClientDocument["_source"][], - options: DocumentModificationContext, - userId: string - ): void; - - /** - * Present a Dialog form to confirm deletion of this Document. - * @param [options] Positioning and sizing options for the resulting dialog - * @return A Promise which resolves to the deleted Document - */ - deleteDialog(options?: object): Promise; - - /** Export entity data to a JSON file which can be saved by the client and later imported into a different session. */ - exportToJSON(): void; - - /** - * Update this Document using a provided JSON string. - * @param json JSON data string - * @return The updated Document - */ - importFromJSON(json: string): Promise; - - /** Render an import dialog for updating the data related to this Document through an exported JSON file */ - importFromJSONDialog(): Promise; - - /** - * Transform the Document data to be stored in a Compendium pack. - * Remove any features of the data which are world-specific. - * This function is asynchronous in case any complex operations are required prior to exporting. - * @param [pack] A specific pack being exported to - * @return A data object of cleaned data suitable for compendium import - */ - toCompendium(pack: CompendiumCollection): this["_source"]; - - /** - * Serialize salient information about this Document when dragging it. - * @return An object of drag data. - */ - toDragData(): { type: string; [key: string]: unknown }; -} diff --git a/types/foundry/client/documents/mixins/index.d.ts b/types/foundry/client/documents/mixins/index.d.ts deleted file mode 100644 index b03c800f6e0..00000000000 --- a/types/foundry/client/documents/mixins/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import "./canvas-document-mixin"; -import "./canvas-document-mixin2"; -import "./client-document-mixin"; -import "./client-document-mixin2"; diff --git a/types/foundry/client/documents/note-document.d.ts b/types/foundry/client/documents/note-document.d.ts index ca39f927dab..1f607b327b1 100644 --- a/types/foundry/client/documents/note-document.d.ts +++ b/types/foundry/client/documents/note-document.d.ts @@ -1,4 +1,4 @@ -import { NoteDocumentConstructor } from "./constructors"; +import { CanvasBaseNote } from "./client-base-mixes.mjs"; declare global { /** @@ -8,7 +8,7 @@ declare global { * @see {@link documents.Scene} The Scene document type which contains Note embedded documents * @see {@link applications.NoteConfig} The Note configuration application */ - class NoteDocument extends NoteDocumentConstructor { + class NoteDocument extends CanvasBaseNote { /** The associated JournalEntry which is referenced by this Note */ get entry(): JournalEntry; @@ -16,9 +16,7 @@ declare global { get label(): string; } - interface NoteDocument { - readonly parent: Scene | null; - - readonly _object: Note; + interface NoteDocument extends CanvasBaseNote { + readonly _object: Note | null; } } diff --git a/types/foundry/client/documents/playlist-sound.d.ts b/types/foundry/client/documents/playlist-sound.d.ts index 8c641843458..c78d2ffdef5 100644 --- a/types/foundry/client/documents/playlist-sound.d.ts +++ b/types/foundry/client/documents/playlist-sound.d.ts @@ -1,4 +1,4 @@ -import { PlaylistSoundConstructor } from "./constructors"; +import { ClientBasePlaylistSound } from "./client-base-mixes.mjs"; declare global { /** @@ -10,11 +10,10 @@ declare global { * @see {@link documents.Playlist} The Playlist document which contains PlaylistSound embedded documents * @see {@link Sound} The Sound API which manages web audio playback */ - class PlaylistSound extends PlaylistSoundConstructor { - /** @override */ + class PlaylistSound extends ClientBasePlaylistSound { constructor( - data: PreCreate, - context?: DocumentConstructionContext + data: PreCreate, + context?: DocumentConstructionContext ); /** The Sound which manages playback for this playlist sound */ @@ -32,10 +31,6 @@ declare global { /** @todo fill the rest of this in */ } - interface PlaylistSound { - readonly parent: Playlist | null; - } - /** @todo: fill in */ class Sound {} } diff --git a/types/foundry/client/documents/playlist.d.ts b/types/foundry/client/documents/playlist.d.ts index ba76b2abbf0..c5f26943b60 100644 --- a/types/foundry/client/documents/playlist.d.ts +++ b/types/foundry/client/documents/playlist.d.ts @@ -1,17 +1,15 @@ -import { PlaylistConstructor } from "./constructors"; +import { ClientBasePlaylist } from "./client-base-mixes.mjs"; declare global { /** - * The client-side Playlist document which extends the common BasePlaylist abstraction. - * Each Playlist document contains PlaylistData which defines its data schema. - * @see {@link data.PlaylistData} The Playlist data schema - * @see {@link documents.Playlists} The world-level collection of Playlist documents - * @see {@link embedded.PlaylistSound} The PlaylistSound embedded document within a parent Playlist - * @see {@link applications.PlaylistConfig} The Playlist configuration application + * The client-side Playlist document which extends the common BasePlaylist model. + * + * @see {@link Playlists} The world-level collection of Playlist documents + * @see {@link PlaylistSound} The PlaylistSound embedded document within a parent Playlist + * @see {@link PlaylistConfig} The Playlist configuration application */ - class Playlist extends PlaylistConstructor { - /** @override */ - constructor(data: PreCreate, context?: DocumentConstructionContext); + class Playlist extends ClientBasePlaylist { + constructor(data: PreCreate, context?: DocumentConstructionContext); /** * Each sound which is played within the Playlist has a created Howl instance. @@ -61,7 +59,7 @@ declare global { * @param sound The desired sound that should play * @returns The updated Playlist */ - playSound(sound: PlaylistSound): Promise; + playSound(sound: PlaylistSound): Promise; /** * Stop playback of a specific Sound within this Playlist. @@ -69,7 +67,7 @@ declare global { * @param sound The desired sound that should play * @returns The updated Plaaylist */ - stopSound(sound: PlaylistSound): Promise; + stopSound(sound: PlaylistSound): Promise; /** * End playback for any/all currently playing sounds within the Playlist. * @returns The updated Playlist entity @@ -83,63 +81,65 @@ declare global { cycleMode(): Promise; /** Get the next sound in the cached playback order. For internal use. */ - protected _getNextSound(soundId: string): PlaylistSound; + protected _getNextSound(soundId: string): PlaylistSound; - /** - * Get the previous sound in the cached playback order. For internal use. - */ - protected _getPreviousSound(soundId: string): PlaylistSound; + /** Get the previous sound in the cached playback order. For internal use. */ + protected _getPreviousSound(soundId: string): PlaylistSound; /** Define the sorting order for the Sounds within this Playlist. For internal use. */ - protected _sortSounds(a: PlaylistSound, b: PlaylistSound): number; + protected _sortSounds(a: PlaylistSound, b: PlaylistSound): number; protected override _preUpdate( data: DocumentUpdateData, - options: DocumentModificationContext, + options: DocumentModificationContext, user: User ): Promise; protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; - protected override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; protected override _onCreateEmbeddedDocuments( embeddedName: "PlaylistSound", - documents: PlaylistSound[], - result: foundry.data.PlaylistSoundSource[], - options: DocumentModificationContext, + documents: PlaylistSound[], + result: PlaylistSound["_source"][], + options: DocumentModificationContext, userId: string ): void; protected override _onUpdateEmbeddedDocuments( embeddedName: "PlaylistSound", - documents: PlaylistSound[], - result: foundry.data.PlaylistSoundSource[], - options: DocumentModificationContext, + documents: PlaylistSound[], + result: PlaylistSound["_source"][], + options: DocumentModificationContext, userId: string ): void; protected override _onDeleteEmbeddedDocuments( embeddedName: "PlaylistSound", - documents: ClientDocument[], - result: PlaylistSound[], - options: DocumentModificationContext, + documents: PlaylistSound[], + result: string[], + options: DocumentModificationContext, userId: string ): void; /** Handle callback logic when an individual sound within the Playlist concludes playback naturally */ - protected _onSoundEnd(sound: PlaylistSound): Promise; + protected _onSoundEnd(sound: PlaylistSound): Promise; /** * Handle callback logic when playback for an individual sound within the Playlist is started. * Schedule auto-preload of next track */ - protected _onSoundStart(sound: PlaylistSound): Promise; + protected _onSoundStart(sound: PlaylistSound): Promise; + + override toCompendium(pack: CompendiumCollection): this["_source"]; + } - override toCompendium(pack: CompendiumCollection): foundry.data.PlaylistSource; + interface Playlist extends ClientBasePlaylist { + readonly sounds: foundry.abstract.EmbeddedCollection>; } } diff --git a/types/foundry/client/documents/roll-table.d.ts b/types/foundry/client/documents/roll-table.d.ts index c5276d0285f..63fecf6d8d0 100644 --- a/types/foundry/client/documents/roll-table.d.ts +++ b/types/foundry/client/documents/roll-table.d.ts @@ -1,4 +1,4 @@ -import { RollTableConstructor } from "./constructors"; +import { ClientBaseRollTable } from "./client-base-mixes.mjs"; declare global { /** @@ -8,7 +8,7 @@ declare global { * @see {@link documents.RollTables} The world-level collection of RollTable documents * @see {@link applications.RollTableConfig} The RollTable configuration application */ - class RollTable extends RollTableConstructor { + class RollTable extends ClientBaseRollTable { /* -------------------------------------------- */ /* Methods */ /* -------------------------------------------- */ @@ -24,15 +24,15 @@ declare global { * @param [options.messageOptions={}] Additional options which customize the created messages */ toMessage( - results: TableResult[], + results: TableResult[], { roll, messageData, messageOptions, }?: { roll?: Roll | null; - messageData?: Partial; - messageOptions?: DocumentModificationContext; + messageData?: Partial; + messageOptions?: ChatMessageModificationContext; } ): Promise; @@ -55,10 +55,10 @@ declare global { }?: { roll?: Roll | null; recursive?: boolean; - results?: TableResult[]; + results?: TableResult[]; displayChat?: boolean; - rollMode?: RollMode | null; - }): Promise; + rollMode?: RollMode | "roll" | null; + }): Promise>; /** * Draw multiple results from a RollTable, constructing a final synthetic Roll as a dice pool of inner rolls. @@ -78,7 +78,7 @@ declare global { displayChat, rollMode, }?: { roll?: Roll | null; recursive?: boolean; displayChat?: boolean; rollMode?: RollMode | null } - ): Promise; + ): Promise>; /** Normalize the probabilities of rolling each item in the RollTable based on their assigned weights */ normalize(): Promise; @@ -113,14 +113,14 @@ declare global { roll?: Roll; recursive?: boolean; _depth?: number; - }): Promise; + }): Promise>; /** * Get an Array of valid results for a given rolled total * @param value The rolled value * @return An Array of results */ - getResultsForRoll(value: number): TableResult[]; + getResultsForRoll(value: number): TableResult[]; /* -------------------------------------------- */ /* Event Handlers */ @@ -128,17 +128,17 @@ declare global { protected override _onCreateEmbeddedDocuments( embeddedName: "TableResult", - documents: TableResult[], - result: foundry.data.TableResultSource[], - options: DocumentModificationContext, + documents: TableResult[], + result: TableResult["_source"][], + options: DocumentModificationContext, userId: string ): void; protected override _onDeleteEmbeddedDocuments( embeddedName: "TableResult", - documents: TableResult[], - result: foundry.data.TableResultSource[], - options: DocumentModificationContext, + documents: TableResult[], + result: string[], + options: DocumentModificationContext, userId: string ): void; @@ -146,14 +146,18 @@ declare global { /* Importing and Exporting */ /* -------------------------------------------- */ - override toCompendium(pack: CompendiumCollection): foundry.data.RollTableSource; + override toCompendium(pack: CompendiumCollection): this["_source"]; /** * Create a new RollTable entity using all of the Entities from a specific Folder as new results. * @param folder The Folder entity from which to create a roll table * @param options Additional options passed to the RollTable.create method */ - static fromFolder(folder: Folder, options?: DocumentModificationContext): Promise; + static fromFolder(folder: Folder, options?: DocumentModificationContext): Promise; + } + + interface RollTable extends ClientBaseRollTable { + readonly results: foundry.abstract.EmbeddedCollection>; } /** @@ -161,8 +165,8 @@ declare global { * @property roll The Dice roll which generated the draw * @property results An array of drawn TableResult documents */ - interface RollTableDraw { + interface RollTableDraw { roll: Roll; - results: TableResult[]; + results: TableResult[]; } } diff --git a/types/foundry/client/documents/scene.d.ts b/types/foundry/client/documents/scene.d.ts index 538d59efbb4..2f7c1f57681 100644 --- a/types/foundry/client/documents/scene.d.ts +++ b/types/foundry/client/documents/scene.d.ts @@ -1,4 +1,4 @@ -import { SceneConstructor } from "./constructors"; +import { ClientBaseScene } from "./client-base-mixes.mjs"; declare global { /** @@ -6,36 +6,22 @@ declare global { * Each Scene document contains SceneData which defines its data schema. * @param [data={}] Initial data provided to construct the Scene document */ - class Scene extends SceneConstructor { - constructor(data: PreCreate, context?: DocumentConstructionContext); - - /** Track whether the scene is the active view */ - protected _view: boolean; - + class Scene extends ClientBaseScene { /** * Track the viewed position of each scene (while in memory only, not persisted) * When switching back to a previously viewed scene, we can automatically pan to the previous position. */ protected _viewPosition: {} | { x: number; y: number; scale: number }; - /** A convenience accessor for whether the Scene is currently active */ - get active(): boolean; + /** Track whether the scene is the active view */ + protected _view: boolean; - /** A convenience accessor for the background image of the Scene */ - get img(): string; + /** Provide a thumbnail image path used to represent this document. */ + get thumbnail(): string; /** A convenience accessor for whether the Scene is currently viewed */ get isView(): boolean; - /** A reference to the JournalEntry entity associated with this Scene, or null */ - get journal(): JournalEntry | null; - - /** A reference to the Playlist entity for this Scene, or null */ - get playlist(): Playlist | null; - - /** A reference to the PlaylistSound document which should automatically play for this Scene, if any */ - get playlistSound(): PlaylistSound | null; - /* -------------------------------------------- */ /* Scene Methods */ /* -------------------------------------------- */ @@ -47,15 +33,12 @@ declare global { activate(): Promise; override clone( - data: DeepPartial | undefined, + data: DeepPartial | undefined, options: { save: true; keepId?: boolean } ): Promise; + override clone(data?: DeepPartial, options?: { save?: false; keepId?: boolean }): this; override clone( - data?: DeepPartial, - options?: { save?: false; keepId?: boolean } - ): this; - override clone( - data?: DeepPartial, + data?: DeepPartial, options?: { save?: boolean; keepId?: boolean } ): this | Promise; @@ -65,32 +48,28 @@ declare global { override prepareBaseData(): void; protected override _preCreate( - data: PreDocumentId, - options: DocumentModificationContext, + data: PreDocumentId, + options: DocumentModificationContext, user: User ): Promise; protected override _onCreate( - data: foundry.data.SceneSource, - options: DocumentModificationContext, + data: this["_source"], + options: DocumentModificationContext, userId: string ): void; protected override _preUpdate( data: DocumentUpdateData, - options: DocumentModificationContext, + options: SceneUpdateContext, user: User ): Promise; - override _onUpdate( - changed: DeepPartial, - options: DocumentModificationContext, - userId: string - ): void; + override _onUpdate(changed: DeepPartial, options: SceneUpdateContext, userId: string): void; - protected override _preDelete(options: DocumentModificationContext, user: User): Promise; + protected override _preDelete(options: DocumentModificationContext, user: User): Promise; - protected override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; /** * Handle Scene activation workflow if the active state is changed to true @@ -100,60 +79,60 @@ declare global { protected override _preCreateEmbeddedDocuments( embeddedName: "Token", - result: foundry.data.TokenSource[], - options: SceneEmbeddedModificationContext, + result: foundry.documents.TokenSource[], + options: SceneEmbeddedModificationContext, userId: string ): void; protected override _onCreateEmbeddedDocuments( embeddedName: "Token", - documents: TokenDocument[], - result: foundry.data.TokenSource[], - options: SceneEmbeddedModificationContext, + documents: TokenDocument[], + result: foundry.documents.TokenSource[], + options: SceneEmbeddedModificationContext, userId: string ): void; protected override _onCreateEmbeddedDocuments( embeddedName: string, - documents: ClientDocument[], + documents: foundry.abstract.Document[], result: object[], - options: SceneEmbeddedModificationContext, + options: SceneEmbeddedModificationContext, userId: string ): void; protected override _preUpdateEmbeddedDocuments( embeddedName: "Token", - result: foundry.data.TokenSource[], - options: SceneEmbeddedModificationContext, + result: TokenDocument["_source"][], + options: SceneEmbeddedModificationContext, userId: string ): void; protected override _onUpdateEmbeddedDocuments( embeddedName: "Token", - documents: TokenDocument[], - result: TokenDocument["_source"][], - options: SceneEmbeddedModificationContext, + documents: TokenDocument[], + result: TokenDocument["_source"][], + options: SceneEmbeddedModificationContext, userId: string ): void; protected override _preDeleteEmbeddedDocuments( embeddedName: "Token", - result: TokenDocument["_source"][], - options: SceneEmbeddedModificationContext, + result: string[], + options: SceneEmbeddedModificationContext, userId: string ): void; protected override _onDeleteEmbeddedDocuments( embeddedName: "Token", - documents: TokenDocument[], - result: foundry.data.TokenSource[], - options: SceneEmbeddedModificationContext, + documents: TokenDocument[], + result: string[], + options: SceneEmbeddedModificationContext, userId: string ): void; protected override _onDeleteEmbeddedDocuments( embeddedName: string, - documents: ClientDocument[], - result: object[], - options: SceneEmbeddedModificationContext, + documents: foundry.abstract.Document[], + result: string[], + options: SceneEmbeddedModificationContext, userId: string ): void; @@ -179,15 +158,13 @@ declare global { } interface Scene { - readonly data: foundry.data.SceneData; - - readonly drawings: foundry.abstract.EmbeddedCollection; - readonly lights: foundry.abstract.EmbeddedCollection; - readonly notes: foundry.abstract.EmbeddedCollection; - readonly sounds: foundry.abstract.EmbeddedCollection; - readonly templates: foundry.abstract.EmbeddedCollection; - readonly tokens: foundry.abstract.EmbeddedCollection; - readonly tiles: foundry.abstract.EmbeddedCollection; + readonly drawings: foundry.abstract.EmbeddedCollection>; + readonly lights: foundry.abstract.EmbeddedCollection>; + readonly notes: foundry.abstract.EmbeddedCollection>; + readonly sounds: foundry.abstract.EmbeddedCollection>; + readonly templates: foundry.abstract.EmbeddedCollection>; + readonly tokens: foundry.abstract.EmbeddedCollection>; + readonly tiles: foundry.abstract.EmbeddedCollection>; readonly walls: foundry.abstract.EmbeddedCollection>; _sheet: SceneConfig | null; @@ -200,43 +177,43 @@ declare global { updateEmbeddedDocuments( embeddedName: "Token", - updateData: EmbeddedDocumentUpdateData[], - options?: SceneEmbeddedModificationContext + updateData: EmbeddedDocumentUpdateData>[], + options?: SceneEmbeddedModificationContext ): Promise[]>; updateEmbeddedDocuments( embeddedName: "AmbientLight", - updateData: EmbeddedDocumentUpdateData[], - options?: SceneEmbeddedModificationContext + updateData: EmbeddedDocumentUpdateData>[], + options?: SceneEmbeddedModificationContext ): Promise[]>; updateEmbeddedDocuments( embeddedName: "AmbientSound", - updateData: EmbeddedDocumentUpdateData[], - options?: SceneEmbeddedModificationContext + updateData: EmbeddedDocumentUpdateData>[], + options?: SceneEmbeddedModificationContext ): Promise[]>; updateEmbeddedDocuments( embeddedName: "Drawing", - updateData: EmbeddedDocumentUpdateData[], - options?: SceneEmbeddedModificationContext + updateData: EmbeddedDocumentUpdateData>[], + options?: SceneEmbeddedModificationContext ): Promise[]>; updateEmbeddedDocuments( embeddedName: "MeasuredTemplate", - updateData: EmbeddedDocumentUpdateData[], - options?: SceneEmbeddedModificationContext + updateData: EmbeddedDocumentUpdateData>[], + options?: SceneEmbeddedModificationContext ): Promise[]>; updateEmbeddedDocuments( embeddedName: "Note", - updateData: EmbeddedDocumentUpdateData[], - options?: SceneEmbeddedModificationContext + updateData: EmbeddedDocumentUpdateData>[], + options?: SceneEmbeddedModificationContext ): Promise[]>; updateEmbeddedDocuments( embeddedName: "Tile", - updateData: EmbeddedDocumentUpdateData[], - options?: SceneEmbeddedModificationContext + updateData: EmbeddedDocumentUpdateData>[], + options?: SceneEmbeddedModificationContext ): Promise[]>; updateEmbeddedDocuments( embeddedName: "Wall", updateData: EmbeddedDocumentUpdateData>[], - options?: SceneEmbeddedModificationContext + options?: SceneEmbeddedModificationContext ): Promise[]>; updateEmbeddedDocuments( embeddedName: @@ -249,15 +226,15 @@ declare global { | "Tile" | "Wall", updateData: - | EmbeddedDocumentUpdateData[] - | EmbeddedDocumentUpdateData[] - | EmbeddedDocumentUpdateData[] - | EmbeddedDocumentUpdateData[] - | EmbeddedDocumentUpdateData[] - | EmbeddedDocumentUpdateData[] - | EmbeddedDocumentUpdateData[] + | EmbeddedDocumentUpdateData>[] + | EmbeddedDocumentUpdateData>[] + | EmbeddedDocumentUpdateData>[] + | EmbeddedDocumentUpdateData>[] + | EmbeddedDocumentUpdateData>[] + | EmbeddedDocumentUpdateData>[] + | EmbeddedDocumentUpdateData>[] | EmbeddedDocumentUpdateData>[], - options?: SceneEmbeddedModificationContext + options?: SceneEmbeddedModificationContext ): Promise< | CollectionValue[] | CollectionValue[] @@ -270,7 +247,7 @@ declare global { >; } - interface SceneUpdateContext extends DocumentModificationContext { + interface SceneUpdateContext extends DocumentModificationContext { animateDarkness?: number; } } diff --git a/types/foundry/client/documents/table-result.d.ts b/types/foundry/client/documents/table-result.d.ts index ebb857bbad2..8444c3fd442 100644 --- a/types/foundry/client/documents/table-result.d.ts +++ b/types/foundry/client/documents/table-result.d.ts @@ -1,14 +1,12 @@ -import { TableResultConstructor } from "./constructors"; +import { ClientBaseTableResult } from "./client-base-mixes.mjs"; + declare global { /** - * The TableResult embedded document within a RollTable document which extends the BaseRollTable abstraction. - * Each TableResult belongs to the results collection of a RollTable entity. - * Each TableResult contains a TableResultData object which provides its source data. + * The client-side TableResult document which extends the common BaseTableResult document model. * - * @see {@link data.TableResultData} The TableResult data schema - * @see {@link documents.RollTable} The RollTable document which contains TableResult embedded documents + * @see {@link RollTable} The RollTable document type which contains TableResult documents */ - class TableResult extends TableResultConstructor { + class TableResult extends ClientBaseTableResult { /** A path reference to the icon image used to represent this result */ get icon(): string; @@ -18,8 +16,4 @@ declare global { */ getChatText(): string; } - - interface TableResult { - readonly parent: RollTable | null; - } } diff --git a/types/foundry/client/documents/tile-document.d.ts b/types/foundry/client/documents/tile-document.d.ts index 9c8bb44709f..0ca57262d7e 100644 --- a/types/foundry/client/documents/tile-document.d.ts +++ b/types/foundry/client/documents/tile-document.d.ts @@ -1,11 +1,9 @@ -import { TileDocumentConstructor } from "./constructors"; +import { CanvasBaseTile } from "./client-base-mixes.mjs"; declare global { - class TileDocument extends TileDocumentConstructor {} + class TileDocument extends CanvasBaseTile {} - interface TileDocument { - readonly parent: Scene | null; - - readonly _object: Tile; + interface TileDocument extends CanvasBaseTile { + readonly _object: Tile | null; } } diff --git a/types/foundry/client/documents/token-document.d.ts b/types/foundry/client/documents/token-document.d.ts index 9990c8a431a..d106e4ee60b 100644 --- a/types/foundry/client/documents/token-document.d.ts +++ b/types/foundry/client/documents/token-document.d.ts @@ -1,12 +1,10 @@ -import { TokenDocumentConstructor } from "./constructors"; - -type _Actor = Actor>; +import { CanvasBaseToken } from "./client-base-mixes.mjs"; declare global { - class TokenDocument extends TokenDocumentConstructor { + class TokenDocument extends CanvasBaseToken { constructor( - data: PreCreate, - context?: TokenDocumentConstructionContext + data: PreCreate, + context?: TokenDocumentConstructionContext> | null> ); /** An array of detection modes which are available to this Token */ @@ -14,18 +12,12 @@ declare global { sort: number; - /** - * A cached reference to the Actor document that this Token modifies. - * This may be a "synthetic" unlinked Token Actor which does not exist in the World. - */ - protected _actor: TActor | null; - /** * A lazily evaluated reference to the Actor this Token modifies. - * If actorLink is true, then the entity is the primary Actor document. - * Otherwise the Actor entity is a synthetic (ephemeral) document constructed using the Token's actorData. + * If actorLink is true, then the document is the primary Actor document. + * Otherwise, the Actor document is a synthetic (ephemeral) document constructed using the Token's actorData. */ - get actor(): TActor | null; + get actor(): Actor | null; /** An indicator for whether or not the current User has full control over this Token document. */ override get isOwner(): boolean; @@ -34,7 +26,7 @@ declare global { get isLinked(): this["actorLink"]; /** Return a reference to a Combatant that represents this Token, if one is present in the current encounter. */ - get combatant(): Combatant | null; + get combatant(): Combatant | null; /** An indicator for whether or not this Token is currently involved in the active combat encounter. */ get inCombat(): boolean; @@ -52,24 +44,21 @@ declare global { protected _prepareDetectionModes(): void; override clone( - data: DeepPartial | undefined, + data: DeepPartial | undefined, options: { save: true; keepId?: boolean } ): Promise; + override clone(data?: DeepPartial, options?: { save?: false; keepId?: boolean }): this; override clone( - data?: DeepPartial, - options?: { save?: false; keepId?: boolean } - ): this; - override clone( - data?: DeepPartial, + data?: DeepPartial, options?: { save?: boolean; keepId?: boolean } ): this | Promise; /** * Create a synthetic Actor using a provided Token instance - * If the Token data is linked, return the true Actor entity + * If the Token data is linked, return the true Actor document * If the Token data is not linked, create a synthetic Actor using the Token's actorData override */ - getActor(): TActor | null; + getActor(): Actor | null; /** * A helper method to retrieve the underlying data behind one of the Token's attribute bars @@ -98,11 +87,10 @@ declare global { * @param options Provided options which modify the update request * @returns The updated un-linked Actor instance */ - modifyActorDocument(update: Record, options: DocumentModificationContext): Promise; - - override getEmbeddedCollection( - embeddedName: "Item" | "ActiveEffect" - ): ReturnType; + modifyActorDocument( + update: Record, + options: DocumentModificationContext + ): Promise[]>; /** * Redirect creation of Documents within a synthetic Token Actor to instead update the tokenData override object. @@ -113,9 +101,9 @@ declare global { */ createActorEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - data: PreCreate[] | Partial[], - options?: DocumentModificationContext - ): ActiveEffect | Item[]; + data: PreCreate[] | Partial[], + options?: DocumentModificationContext + ): ActiveEffect> | Item>[]; /** * Redirect updating of Documents within a synthetic Token Actor to instead update the tokenData override object. @@ -126,9 +114,9 @@ declare global { */ updateActorEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", - updates: EmbeddedDocumentUpdateData[], - options: DocumentModificationContext - ): Promise; + updates: EmbeddedDocumentUpdateData> | Item>>[], + options: DocumentModificationContext + ): Promise>[] | Item>[]>; /** * Redirect deletion of Documents within a synthetic Token Actor to instead update the tokenData override object. @@ -140,8 +128,8 @@ declare global { deleteActorEmbeddedDocuments( embeddedName: "ActiveEffect" | "Item", ids: string[], - options: DocumentModificationContext - ): Promise; + options: DocumentModificationContext + ): Promise>[] | Item>[]>; /* -------------------------------------------- */ /* Event Handlers */ @@ -149,30 +137,30 @@ declare global { protected override _preUpdate( data: DocumentUpdateData, - options: DocumentModificationContext, + options: TokenUpdateContext, user: User ): Promise; /** When the Actor data overrides change for an un-linked Token Actor, simulate the pre-update process. */ protected _preUpdateTokenActor( - data: DocumentUpdateData, - options: TokenUpdateContext, + data: DocumentUpdateData>, + options: TokenUpdateContext, userId: string ): Promise; protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; /** When the base Actor for a TokenDocument changes, we may need to update its Actor instance */ - _onUpdateBaseActor(update?: Record, options?: DocumentModificationContext): void; + _onUpdateBaseActor(update?: Record, options?: DocumentModificationContext): void; /** When the Actor data overrides change for an un-linked Token Actor, simulate the post-update process. */ protected _onUpdateTokenActor( data: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; @@ -183,35 +171,24 @@ declare global { static getTrackedAttributeChoices(attributes: TokenAttributes): TokenAttributes; } - interface TokenDocument { - readonly data: foundry.data.TokenData; - - readonly parent: Scene | null; - - // V10 shim - readonly flags: this["data"]["flags"]; - + interface TokenDocument extends CanvasBaseToken { + get object(): Token | null; + get sheet(): TokenConfig; get uuid(): TokenDocumentUUID; - - _sheet: TokenConfig | null; - - readonly _object: Token | null; } - interface TokenDocumentConstructionContext - extends DocumentConstructionContext { + interface TokenDocumentConstructionContext< + TParent extends Scene | null, + TActor extends Actor> | null + > extends DocumentConstructionContext { actor?: TActor; } - interface TokenUpdateContext extends DocumentModificationContext { + interface TokenUpdateContext extends DocumentModificationContext { action?: "create" | "update" | "delete"; embedded?: { embeddedName: string; hookData: { _id?: string }[] }; } - namespace TokenDocument { - function _canUpdate(user: User, doc: TokenDocument, data: foundry.data.TokenData): boolean; - } - type TokenDocumentUUID = `Scene.${string}.Token.${string}`; interface TokenAttributes { diff --git a/types/foundry/client/documents/user.d.ts b/types/foundry/client/documents/user.d.ts index c2e7fb3fdd3..559d6e01a5a 100644 --- a/types/foundry/client/documents/user.d.ts +++ b/types/foundry/client/documents/user.d.ts @@ -1,21 +1,24 @@ -import { UserConstructor } from "./constructors"; +import { ClientBaseUser } from "./client-base-mixes.mjs"; declare global { /** * The client-side User document which extends the common BaseUser model. * Each User document contains UserData which defines its data schema. * + * @extends documents.BaseUser + * @mixes ClientDocumentMixin + * * @see {@link documents.Users} The world-level collection of User documents * @see {@link applications.UserConfig} The User configuration application */ - class User extends UserConstructor { + class User extends ClientBaseUser { constructor(data: PreCreate, context?: DocumentConstructionContext); /** Track whether the user is currently active in the game */ active: boolean; /** Track references to the current set of Tokens which are targeted by the User */ - targets: Set["object"]>>; + targets: Set; /** Track the ID of the Scene that is currently being viewed by the User */ viewedScene: string | null; @@ -85,15 +88,15 @@ declare global { protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; - protected override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; } - interface User { - character: TActor | null | undefined; + interface User extends ClientBaseUser { + character: Actor | null; } interface UserActivity { diff --git a/types/foundry/client/documents/wall-document.d.ts b/types/foundry/client/documents/wall-document.d.ts index 314568d7483..9c4dbd6c932 100644 --- a/types/foundry/client/documents/wall-document.d.ts +++ b/types/foundry/client/documents/wall-document.d.ts @@ -1,11 +1,9 @@ -import { WallDocumentConstructor } from "./constructors"; +import { CanvasBaseWall } from "./client-base-mixes.mjs"; declare global { - class WallDocument extends WallDocumentConstructor {} + class WallDocument extends CanvasBaseWall {} - interface WallDocument { - readonly parent: TParent; - - readonly _object: Wall; + interface WallDocument extends CanvasBaseWall { + get object(): Wall | null; } } diff --git a/types/foundry/client/game.d.ts b/types/foundry/client/game.d.ts index 0243f7fdd2f..9e20318ad87 100644 --- a/types/foundry/client/game.d.ts +++ b/types/foundry/client/game.d.ts @@ -14,14 +14,14 @@ declare global { * @param socket The open web-socket which should be used to transact game-state data */ class Game< - TActor extends Actor, + TActor extends Actor, TActors extends Actors, - TChatMessage extends ChatMessage, + TChatMessage extends ChatMessage, TCombat extends Combat, - TItem extends Item, + TItem extends Item, TMacro extends Macro, TScene extends Scene, - TUser extends User + TUser extends User > { /** * The named view which is currently active. @@ -36,11 +36,11 @@ declare global { data: { actors: TActor["_source"][]; items: TItem["_source"][]; - macros: foundry.data.MacroSource[]; - messages: foundry.data.ChatMessageSource[]; + macros: TMacro["_source"][]; + messages: TChatMessage["_source"][]; packs: CompendiumMetadata[]; - tables: foundry.data.RollTableSource[]; - users: foundry.documents.UserSource[]; + tables: foundry.documents.RollTableSource[]; + users: TUser["_source"][]; version: string; }; @@ -163,7 +163,9 @@ declare global { * Fetch World data and return a Game instance * @return A Promise which resolves to the created Game instance */ - static create(): Promise, ChatMessage, Combat, Item, Macro, Scene, User>>; + static create(): Promise< + Game, Actors>, ChatMessage, Combat, Item, Macro, Scene, User> + >; /** Request World data from server and return it */ static getWorldData(socket: io.Socket): Promise; diff --git a/types/foundry/client/keyboard/client-keybindings.d.ts b/types/foundry/client/keyboard/client-keybindings.d.ts index f2d7a2d2f5b..64cefe6afdf 100644 --- a/types/foundry/client/keyboard/client-keybindings.d.ts +++ b/types/foundry/client/keyboard/client-keybindings.d.ts @@ -157,7 +157,9 @@ declare global { private static _onToggleCharacterSheet( event: KeyboardEvent, context: KeyboardEventContext - ): ActorSheet | Promise; + ): + | ActorSheet | null>> + | Promise | null>>>; /** * Handle action to target the currently hovered token. @@ -177,7 +179,7 @@ declare global { * @param context The context data of the event * @param layer The Placeables layer */ - private _handleMovement(context: KeyboardEventContext, layer: TokenLayer | BackgroundLayer): void; + private _handleMovement(context: KeyboardEventContext, layer: TokenLayer | TilesLayer): void; /** Handle panning the canvas using CTRL + directional keys */ private _handleCanvasPan(): Promise; diff --git a/types/foundry/client/pixi/canvas.d.ts b/types/foundry/client/pixi/canvas.d.ts index eafbbf29b8b..afb30e6b808 100644 --- a/types/foundry/client/pixi/canvas.d.ts +++ b/types/foundry/client/pixi/canvas.d.ts @@ -92,15 +92,14 @@ declare global { primary: PrimaryCanvasGroup; // Layers - background: BackgroundLayer; controls: ControlsLayer; drawings: DrawingsLayer; - foreground: ForegroundLayer; grid: GridLayer; lighting: TAmbientLight["layer"]; notes: NotesLayer; sounds: SoundsLayer; templates: TMeasuredTemplate["layer"]; + tiles: Tile["layer"]; tokens: TToken["layer"]; walls: WallsLayer; diff --git a/types/foundry/client/pixi/helpers/point-source/base.d.ts b/types/foundry/client/pixi/helpers/point-source/base.d.ts index cd27ade79cc..766462df66c 100644 --- a/types/foundry/client/pixi/helpers/point-source/base.d.ts +++ b/types/foundry/client/pixi/helpers/point-source/base.d.ts @@ -5,7 +5,7 @@ declare global { * A helper class used by the Sight Layer to represent a source of vision or illumination. * @param object The object responsible for the PointSource */ - abstract class PointSource { + abstract class PointSource = Maybe> { constructor(object: TObject); /** The PlaceableObject which is the origin of this PointSource. */ diff --git a/types/foundry/client/pixi/helpers/point-source/light-source.d.ts b/types/foundry/client/pixi/helpers/point-source/light-source.d.ts index e62f2352f42..e73cc343950 100644 --- a/types/foundry/client/pixi/helpers/point-source/light-source.d.ts +++ b/types/foundry/client/pixi/helpers/point-source/light-source.d.ts @@ -5,7 +5,7 @@ declare global { * A specialized subclass of the PointSource abstraction which is used to control the rendering of light sources. * @param object The light-emitting object that generates this light source */ - class LightSource extends PointSource { + class LightSource> extends PointSource { constructor(object: TObject); /** The light or darkness container for this source */ diff --git a/types/foundry/client/pixi/perception/vision-mode.d.ts b/types/foundry/client/pixi/perception/vision-mode.d.ts index bbca4016616..dfc654064ca 100644 --- a/types/foundry/client/pixi/perception/vision-mode.d.ts +++ b/types/foundry/client/pixi/perception/vision-mode.d.ts @@ -49,7 +49,10 @@ declare global { adaptive: boolean; }; defaults: Partial< - Pick + Pick< + TokenDocument["sight"], + "attenuation" | "brightness" | "saturation" | "contrast" | "range" + > >; }; diff --git a/types/foundry/client/pixi/placeable-object/ambient-light.d.ts b/types/foundry/client/pixi/placeable-object/ambient-light.d.ts index 3e5bf6d3b88..523c4e456ef 100644 --- a/types/foundry/client/pixi/placeable-object/ambient-light.d.ts +++ b/types/foundry/client/pixi/placeable-object/ambient-light.d.ts @@ -1,5 +1,5 @@ declare class AmbientLight< - TDocument extends AmbientLightDocument = AmbientLightDocument + TDocument extends AmbientLightDocument = AmbientLightDocument > extends PlaceableObject { constructor(document: TDocument); @@ -36,6 +36,8 @@ declare class AmbientLight< override refresh(): this; + protected override _refresh(options: object): void; + /** Refresh the display of the ControlIcon for this AmbientLight source */ refreshControl(): void; @@ -57,19 +59,19 @@ declare class AmbientLight< /* Socket Listeners and Handlers */ /* -------------------------------------------- */ - override _onCreate( + protected override _onCreate( data: TDocument["_source"], - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; - override _onUpdate( - changed: DocumentUpdateData, - options: DocumentModificationContext, + protected override _onUpdate( + changed: DeepPartial, + options: DocumentModificationContext, userId: string ): void; - override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; /* -------------------------------------------- */ /* Mouse Interaction Handlers */ diff --git a/types/foundry/client/pixi/placeable-object/ambient-sound.d.ts b/types/foundry/client/pixi/placeable-object/ambient-sound.d.ts index ab3f805be41..2f916e7a008 100644 --- a/types/foundry/client/pixi/placeable-object/ambient-sound.d.ts +++ b/types/foundry/client/pixi/placeable-object/ambient-sound.d.ts @@ -1,5 +1,94 @@ declare class AmbientSound< - TDocument extends AmbientSoundDocument = AmbientSoundDocument + TDocument extends AmbientSoundDocument = AmbientSoundDocument > extends PlaceableObject { - protected _draw(): Promise; + /** The Sound which manages playback for this AmbientSound effect */ + sound: Sound | null; + + /** A SoundSource object which manages the area of effect for this ambient sound */ + source: SoundSource; + + static override embeddedName: "AmbientSound"; + + /** Create a Sound used to play this AmbientSound object */ + protected _createSound(): Sound | null; + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** Is this ambient sound is currently audible based on its hidden state and the darkness level of the Scene? */ + get isAudible(): boolean; + + override get bounds(): PIXI.Rectangle; + + /** A convenience accessor for the sound radius in pixels */ + get radius(): number; + + /* -------------------------------------------- */ + /* Methods */ + /* -------------------------------------------- */ + + /** + * Toggle playback of the sound depending on whether or not it is audible + * @param isAudible Is the sound audible? + * @param volume The target playback volume + * @param [options={}] Additional options which affect sound synchronization + * @param [options.fade=250] A duration in milliseconds to fade volume transition + */ + sync(isAudible: boolean, volume: number, options?: { fade?: number }): void; + + /* -------------------------------------------- */ + /* Rendering */ + /* -------------------------------------------- */ + + override clear(): this; + + protected override _draw(): Promise; + + protected override _destroy(options: object): void; + + protected _drawControlIcon(): ControlIcon; + + protected override _refresh(options: object): void; + + /** Refresh the display of the ControlIcon for this AmbientSound source */ + refreshControl(): void; + + /** + * Compute the field-of-vision for an object, determining its effective line-of-sight and field-of-vision polygons + * @param [options={}] Options which modify how the audio source is updated + * @param [options.defer] Defer refreshing the SoundsLayer to manually call that refresh later. + * @param [options.deleted] Indicate that this SoundSource has been deleted. + */ + updateSource(options?: { defer?: boolean; deleted?: boolean }): void; + + /* -------------------------------------------- */ + /* Document Event Handlers */ + /* -------------------------------------------- */ + + protected override _onCreate( + data: TDocument["_source"], + options: DocumentModificationContext, + userId: string + ): void; + + protected override _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, + userId: string + ): void; + + protected override _onDelete(options: DocumentModificationContext, userId: string): void; + + /* -------------------------------------------- */ + /* Interaction Event Handlers */ + /* -------------------------------------------- */ + + protected override _canHUD(user: User, event: PIXI.InteractionEvent): boolean; + + protected override _canConfigure(user: User, event: PIXI.InteractionEvent): boolean; + + protected override _onClickRight(event: PIXI.InteractionEvent): void; + + protected override _onDragLeftMove(event: PIXI.InteractionEvent): void; } diff --git a/types/foundry/client/pixi/placeable-object/base.d.ts b/types/foundry/client/pixi/placeable-object/base.d.ts index f7c500249a6..c5c5fee4fd4 100644 --- a/types/foundry/client/pixi/placeable-object/base.d.ts +++ b/types/foundry/client/pixi/placeable-object/base.d.ts @@ -5,9 +5,7 @@ declare global { * An Abstract Base Class which defines a Placeable Object which represents an Entity placed on the Canvas * @param document The Document instance which is represented by this object */ - abstract class PlaceableObject< - TDocument extends CanvasDocument | CanvasDocument2 = CanvasDocument | CanvasDocument2 - > extends PIXI.Container { + abstract class PlaceableObject extends PIXI.Container { constructor(document: TDocument); /** Retain a reference to the Scene within which this Placeable Object resides */ @@ -158,18 +156,30 @@ declare global { */ refresh(): this; + /** + * The inner _refresh method which must be defined by each PlaceableObject subclass. + * @param options Options which may modify the refresh workflow + */ + protected abstract _refresh(options: object): void; + /** Register pending canvas operations which should occur after a new PlaceableObject of this type is created */ - _onCreate(data: TDocument["_source"], options: DocumentModificationContext, userId: string): void; + protected _onCreate( + data: TDocument["_source"], + options: DocumentModificationContext, + userId: string + ): void; /** Define additional steps taken when an existing placeable object of this type is updated with new data */ - _onUpdate( - changed: DocumentUpdateData, - options: DocumentModificationContext, + + protected _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, userId: string ): void; /** Define additional steps taken when an existing placeable object of this type is deleted */ - _onDelete(options: DocumentModificationContext, userId: string): void; + + protected _onDelete(options: DocumentModificationContext, userId: string): void; /* -------------------------------------------- */ /* Methods */ @@ -289,8 +299,7 @@ declare global { protected _onDragLeftCancel(event: PIXI.InteractionEvent): void; } - interface PlaceableObject - extends PIXI.Container { + interface PlaceableObject extends PIXI.Container { hitArea: PIXI.Rectangle; } } diff --git a/types/foundry/client/pixi/placeable-object/drawing.d.ts b/types/foundry/client/pixi/placeable-object/drawing.d.ts index 99310a64821..7397bf99cae 100644 --- a/types/foundry/client/pixi/placeable-object/drawing.d.ts +++ b/types/foundry/client/pixi/placeable-object/drawing.d.ts @@ -2,7 +2,9 @@ * The Drawing object is an implementation of the PlaceableObject container. * Each Drawing is a placeable object in the DrawingsLayer. */ -declare class Drawing extends PlaceableObject { +declare class Drawing< + TDocument extends DrawingDocument = DrawingDocument +> extends PlaceableObject { constructor(document: TDocument); /** The inner drawing container */ @@ -57,6 +59,8 @@ declare class Drawing exten override refresh(): this; + protected override _refresh(options: object): void; + /** Draw rectangular shapes */ protected _drawRectangle(): void; @@ -97,12 +101,13 @@ declare class Drawing exten protected override _onRelease(options?: object): void; - override _onDelete(options: DocumentModificationContext, userId: string): void; + override _onDelete(options: DocumentModificationContext, userId: string): void; /** Handle text entry in an active text tool */ protected _onDrawingTextKeydown(event: KeyboardEvent): void; } -declare interface Drawing { +declare interface Drawing = DrawingDocument> + extends PlaceableObject { get layer(): DrawingsLayer; } diff --git a/types/foundry/client/pixi/placeable-object/measured-template.d.ts b/types/foundry/client/pixi/placeable-object/measured-template.d.ts index af4666018c9..a6ab2f0f4e9 100644 --- a/types/foundry/client/pixi/placeable-object/measured-template.d.ts +++ b/types/foundry/client/pixi/placeable-object/measured-template.d.ts @@ -17,7 +17,7 @@ * }); */ declare class MeasuredTemplate< - TDocument extends MeasuredTemplateDocument = MeasuredTemplateDocument + TDocument extends MeasuredTemplateDocument = MeasuredTemplateDocument > extends PlaceableObject { /** The template shape used for testing point intersection */ shape: PIXI.Circle | PIXI.Ellipse | PIXI.Polygon | PIXI.Rectangle | PIXI.RoundedRectangle; @@ -76,6 +76,8 @@ declare class MeasuredTemplate< override refresh(): this; + protected override _refresh(options: object): void; + /** Get a Circular area of effect given a radius of effect */ protected _getCircleShape(distance: number): PIXI.Circle; @@ -117,16 +119,17 @@ declare class MeasuredTemplate< /* Socket Listeners and Handlers */ /* -------------------------------------------- */ - override _onUpdate( + protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; - override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; } -declare interface MeasuredTemplate - extends PlaceableObject { +declare interface MeasuredTemplate< + TDocument extends MeasuredTemplateDocument = MeasuredTemplateDocument +> extends PlaceableObject { get layer(): TemplateLayer; } diff --git a/types/foundry/client/pixi/placeable-object/note.d.ts b/types/foundry/client/pixi/placeable-object/note.d.ts index ce02b83dc19..11898ef78e2 100644 --- a/types/foundry/client/pixi/placeable-object/note.d.ts +++ b/types/foundry/client/pixi/placeable-object/note.d.ts @@ -3,7 +3,9 @@ * Each Note links to a JournalEntry document and represents its location on the map. * @todo fill in ... some day */ -declare class Note extends PlaceableObject { +declare class Note< + TDocument extends NoteDocument = NoteDocument +> extends PlaceableObject { static override embeddedName: "Note"; override get bounds(): PIXI.Rectangle; @@ -41,19 +43,22 @@ declare class Note extends Placea override refresh(): this; + protected override _refresh(options: object): void; + /* -------------------------------------------- */ /* Event Handlers */ /* -------------------------------------------- */ - override _onUpdate( + protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; protected override _canHover(user: User): boolean; } -declare interface Note extends PlaceableObject { +declare interface Note = NoteDocument> + extends PlaceableObject { get layer(): NotesLayer; } diff --git a/types/foundry/client/pixi/placeable-object/tile.d.ts b/types/foundry/client/pixi/placeable-object/tile.d.ts index 262e11e0d4d..d365557482c 100644 --- a/types/foundry/client/pixi/placeable-object/tile.d.ts +++ b/types/foundry/client/pixi/placeable-object/tile.d.ts @@ -2,15 +2,12 @@ export {}; declare global { /** - * A Tile is an implementation of PlaceableObject which represents a static piece of artwork or prop within the Scene. - * Tiles are drawn inside a {@link BackgroundLayer} container. - * - * @see {@link TileDocument} - * @see {@link BackgroundLayer} - * @see {@link TileSheet} - * @see {@link TileHUD} + * A PlaceablesLayer designed for rendering the visual Scene for a specific vertical cross-section. + * @category - Canvas */ - class Tile extends PlaceableObject { + class Tile< + TDocument extends TileDocument = TileDocument + > extends PlaceableObject { /* -------------------------------------------- */ /* Attributes */ /* -------------------------------------------- */ @@ -72,10 +69,10 @@ declare global { override destroy(options: object): void; - /** - * @param [refreshPerception=false] Also refresh the perception layer. - */ - override refresh({ refreshPerception }?: { refreshPerception?: boolean }): this; + /** @param [options.refreshPerception=false] Also refresh the perception layer. */ + override refresh(options?: { refreshPerception?: boolean }): this; + + protected override _refresh(options: { refreshPerception?: boolean }): void; /** Refresh the display of the Tile border */ protected _refreshBorder(b: PIXI.Rectangle): void; @@ -89,11 +86,11 @@ declare global { override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; - override _onDelete(options: DocumentModificationContext, userId: string): void; + override _onDelete(options: DocumentModificationContext, userId: string): void; /** * Update wall states and refresh lighting and vision when a tile becomes a roof, or when an existing roof tile's @@ -169,10 +166,11 @@ declare global { * Create a preview tile with a background texture instead of an image * @param data Initial data with which to create the preview Tile */ - static createPreview(data: DeepPartial): Tile; + static createPreview(data: DeepPartial): Tile; } - interface Tile extends PlaceableObject { + interface Tile = TileDocument> + extends PlaceableObject { get layer(): TilesLayer; } } diff --git a/types/foundry/client/pixi/placeable-object/token.d.ts b/types/foundry/client/pixi/placeable-object/token.d.ts index 073eac29473..c8697ef88e7 100644 --- a/types/foundry/client/pixi/placeable-object/token.d.ts +++ b/types/foundry/client/pixi/placeable-object/token.d.ts @@ -2,7 +2,9 @@ export {}; declare global { /** A Token is an implementation of PlaceableObject that represents an Actor within a viewed Scene on the game canvas. */ - class Token extends PlaceableObject { + class Token< + TDocument extends TokenDocument = TokenDocument + > extends PlaceableObject { constructor(document: TDocument); /** A reference to an animation that is currently in progress for this Token, if any */ @@ -221,6 +223,8 @@ declare global { /** Update display of the Token, pulling latest data and re-rendering the display of Token components */ refresh(): this; + protected override _refresh(options: object): void; + /** Draw the Token border, taking into consideration the grid type and border color */ protected _refreshBorder(): void; @@ -447,27 +451,27 @@ declare global { /* Event Listeners and Handlers */ /* -------------------------------------------- */ - override _onCreate( + protected override _onCreate( data: TDocument["_source"], - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; - override _onUpdate( + protected override _onUpdate( changed: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; /** Control updates to the appearance of the Token and its linked TokenMesh when a data update occurs. */ protected _onUpdateAppearance( - data: DeepPartial, + data: DeepPartial, changed: Set, - options: DocumentModificationContext + options: DocumentModificationContext ): Promise; /** Define additional steps taken when an existing placeable object of this type is deleted */ - override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; protected override _canControl(user: User, event?: PIXI.InteractionEvent): boolean; @@ -505,7 +509,8 @@ declare global { protected override _onDragEnd(): void; } - interface Token extends PlaceableObject { + interface Token = TokenDocument> + extends PlaceableObject { get layer(): TokenLayer; } diff --git a/types/foundry/client/pixi/placeable-object/wall.d.ts b/types/foundry/client/pixi/placeable-object/wall.d.ts index 8117970610e..2d459d5311e 100644 --- a/types/foundry/client/pixi/placeable-object/wall.d.ts +++ b/types/foundry/client/pixi/placeable-object/wall.d.ts @@ -58,6 +58,8 @@ declare class Wall> extends Placeab refresh(): this; + protected override _refresh(options: object): void; + /** * Compute an approximate Polygon which encloses the line segment providing a specific hitArea for the line * @param coords The original wall coordinates @@ -104,19 +106,19 @@ declare class Wall> extends Placeab /* Socket Listeners and Handlers */ /* -------------------------------------------- */ - override _onCreate( - data: foundry.data.WallSource, - options: DocumentModificationContext, + protected override _onCreate( + data: TDocument["_source"], + options: DocumentModificationContext, userId: string ): void; - override _onUpdate( - changed: DocumentUpdateData, - options: DocumentModificationContext, + protected override _onUpdate( + changed: DeepPartial, + options: DocumentModificationContext, userId: string ): void; - override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext, userId: string): void; /** * Callback actions when a wall that contains a door is moved or its state is changed diff --git a/types/foundry/client/pixi/placeables-layer/base.d.ts b/types/foundry/client/pixi/placeables-layer/base.d.ts index 482dc2d2a58..ab90b03b265 100644 --- a/types/foundry/client/pixi/placeables-layer/base.d.ts +++ b/types/foundry/client/pixi/placeables-layer/base.d.ts @@ -114,13 +114,14 @@ declare global { * Simultaneously rotate multiple PlaceableObjects using a provided angle or incremental. * This executes a single database operation using Scene.update. * If rotating only a single object, it is better to use the PlaceableObject.rotate instance method. - - * @param angle A target angle of rotation (in degrees) where zero faces "south" - * @param delta An incremental angle of rotation (in degrees) - * @param snap Snap the resulting angle to a multiple of some increment (in degrees) - * @param ids An Array or Set of object IDs to target for rotation - - * @return The resulting Promise from the Scene.update operation + * + * @param options Options which configure how multiple objects are rotated + * @param [options.angle] A target angle of rotation (in degrees) where zero faces "south" + * @param [options.delta] An incremental angle of rotation (in degrees) + * @param [options.snap] Snap the resulting angle to a multiple of some increment (in degrees) + * @param [options.ids] An Array of object IDs to target for rotation + * + * @return An array of objects which were rotated */ rotateMany({ angle, @@ -131,20 +132,21 @@ declare global { angle?: number; delta?: number; snap?: number; - ids?: number[] | Set; - }): Promise; + ids?: string[]; + }): Promise; /** * Simultaneously move multiple PlaceableObjects via keyboard movement offsets. * This executes a single database operation using Scene.update. * If moving only a single object, this will delegate to PlaceableObject.update for performance reasons. * - * @param dx The number of incremental grid units in the horizontal direction - * @param dy The number of incremental grid units in the vertical direction - * @param rotate Rotate the token to the keyboard direction instead of moving - * @param ids An Array or Set of object IDs to target for rotation + * @param options Options which configure how multiple objects are moved + * @param [options.dx=0] The number of incremental grid units in the horizontal direction + * @param [options.dy=0] The number of incremental grid units in the vertical direction + * @param [options.rotate=false] Rotate the token to the keyboard direction instead of moving + * @param [options.ids] An Array of object IDs to target for movement * - * @return The resulting Promise from the Scene.update operation + * @returns An array of objects which were moved during the operation */ moveMany({ dx, @@ -155,40 +157,20 @@ declare global { dx?: number; dy?: number; rotate?: boolean; - ids?: number[] | Set; - }): Promise; + ids?: string[]; + }): Promise; /** * Undo a change to the objects in this layer * This method is typically activated using CTRL+Z while the layer is active + * @returns An array of documents which were modified by the undo operation */ - undoHistory(): Promise; - - /** - * Update multiple embedded entities in a parent Entity collection using an Array of provided data - * - * @param data An Array of update data Objects which provide incremental data - * @param options Additional options which customize the update workflow - * - * @return A Promise which resolves to the returned socket response (if successful) - */ - updateMany(data: any[], options?: any): Promise; - - /** - * Simultaneously delete multiple PlaceableObjects. - * This executes a single database operation using Scene.update. - * If deleting only a single object, this will delegate to PlaceableObject.delete for performance reasons. - * - * @param ids An Array of object IDs to target for deletion - * @param options Additional options which customize the update workflow - * - * @return A Promise which resolves to the returned socket response (if successful) - */ - deleteMany(ids: number[], options?: any): Promise; + undoHistory(): Promise; /** * A helper method to prompt for deletion of all PlaceableObject instances within the Scene * Renders a confirmation dialogue to confirm with the requester that all objects will be deleted + * @returns An array of Document objects which were deleted by the operation */ deleteAll(): Promise; @@ -250,11 +232,9 @@ declare global { * @return An array of updated data once the operation is complete */ updateAll( - transformation: ( - document: TObject - ) => DocumentUpdateData | DocumentUpdateData, + transformation: (document: TObject) => Record, condition?: Function | null, - options?: DocumentModificationContext + options?: DocumentModificationContext ): Promise; /* -------------------------------------------- */ diff --git a/types/foundry/client/pixi/placeables-layer/drawings-layer.d.ts b/types/foundry/client/pixi/placeables-layer/drawings-layer.d.ts index 4db549e0f75..5d8fd2b9bb3 100644 --- a/types/foundry/client/pixi/placeables-layer/drawings-layer.d.ts +++ b/types/foundry/client/pixi/placeables-layer/drawings-layer.d.ts @@ -1,6 +1,7 @@ /** * The DrawingsLayer subclass of PlaceablesLayer. - * This layer implements a container for drawings which are rendered immediately above the BackgroundLayer. * + * This layer implements a container for drawings. + * @category - Canvas * @todo: fill in */ declare class DrawingsLayer extends PlaceablesLayer {} diff --git a/types/foundry/client/pixi/placeables-layer/map-layer/background-layer.d.ts b/types/foundry/client/pixi/placeables-layer/map-layer/background-layer.d.ts deleted file mode 100644 index 445ef27ffc7..00000000000 --- a/types/foundry/client/pixi/placeables-layer/map-layer/background-layer.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** An extension of the MapLayer that displays underfoot in the background of the Scene. */ -declare class BackgroundLayer extends MapLayer { - /** The outline of the scene */ - outline: PIXI.Graphics; - - /* -------------------------------------------- */ - /* Layer Methods */ - /* -------------------------------------------- */ - - override draw(): Promise; - - /** Draw a background outline which emphasizes what portion of the canvas is playable space and what is buffer. */ - protected _drawOutline(): PIXI.Graphics; - - override getDocuments(): TileDocument[]; - - override getZIndex(): number; - - override storeHistory(type: string, data: Record): void; -} diff --git a/types/foundry/client/pixi/placeables-layer/map-layer/base.d.ts b/types/foundry/client/pixi/placeables-layer/map-layer/base.d.ts deleted file mode 100644 index 6e2bc3b5857..00000000000 --- a/types/foundry/client/pixi/placeables-layer/map-layer/base.d.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * A PlaceablesLayer designed for rendering the visual Scene for a specific vertical cross-section. - * Each MapLayer contains a single background image as well as an arbitrary number of Tile objects. - */ -declare abstract class MapLayer extends PlaceablesLayer { - constructor({ bgPath, level }?: { bgPath?: string; level?: number }); - - /** The numeric Scene level to which this layer belongs */ - level: number; - - /** The background source path */ - bgPath: VideoFilePath; - - /** The layer background image */ - bg: PIXI.Sprite; - - static documentName: "Tile"; - - /* -------------------------------------------- */ - /* Layer Attributes */ - /* -------------------------------------------- */ - - static override get layerOptions(): MapLayerOptions; - - /** Return the base HTML image or video element which is used to generate the background Sprite.*/ - get bgSource(): HTMLImageElement | HTMLVideoElement; - - get hud(): TileHUD; - - /** Is the background texture used in this layer a video? */ - get isVideo(): boolean; - - /** An array of Tile objects which are rendered within the objects container */ - get tiles(): Tile; - - /* -------------------------------------------- */ - /* Layer Methods */ - /* -------------------------------------------- */ - - override deactivate(): this; - - override tearDown(): Promise; - - /* -------------------------------------------- */ - /* Layer Rendering */ - /* -------------------------------------------- */ - - override draw(): Promise; - - /** - * Draw the background Sprite for the layer, aligning its dimensions with those configured for the canvas. - * @returns The rendered Sprite, or undefined if no background is present - */ - protected _drawBackground(): PIXI.Sprite | undefined; - - /* -------------------------------------------- */ - /* Event Handlers */ - /* -------------------------------------------- */ - - protected override _onDragLeftStart(event: PIXI.InteractionEvent): Promise; - - protected override _onDragLeftMove(event: PIXI.InteractionEvent): Promise; - - protected override _onDragLeftDrop(event: PIXI.InteractionEvent): Promise; - - protected override _onDragLeftCancel(event: PIXI.InteractionEvent): void; - - /** - * Handle drop events for Tile data on the Tiles Layer - * @param event The concluding drag event - * @param data The extracted Tile data - */ - protected _onDropData(event: PIXI.InteractionEvent, data: Record): Promise; - - /** - * Prepare the data object when a new Tile is dropped onto the canvas - * @param event The concluding drag event - * @param data The extracted Tile data - * @returns The prepared data to create - */ - protected _getDropData( - event: PIXI.InteractionEvent, - data: foundry.data.TileSource - ): Promise; -} - -declare interface MapLayerOptions extends PlaceablesLayerOptions { - name: string; - zIndex: number; - controllableObjects: true; - rotatableObjects: true; -} diff --git a/types/foundry/client/pixi/placeables-layer/map-layer/foreground-layer.d.ts b/types/foundry/client/pixi/placeables-layer/map-layer/foreground-layer.d.ts deleted file mode 100644 index 3c3003fdec1..00000000000 --- a/types/foundry/client/pixi/placeables-layer/map-layer/foreground-layer.d.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** An extension of the MapLayer that displays overhead in the foreground of the Scene. */ -declare class ForegroundLayer extends MapLayer { - occlusionMask: PIXI.Container; - - static get layerOptions(): MapLayerOptions & { - name: "foreground"; - }; - - /** Get an array of overhead Tile objects which are roofs */ - get roofs(): PIXI.DisplayObject[]; - - /** Determine whether to display roofs */ - get displayRoofs(): boolean; - - /* -------------------------------------------- */ - /* Layer Methods */ - /* -------------------------------------------- */ - - override draw(): Promise; - - /** - * Draw the container used to cache the position of Token occlusion shapes to a RenderTexture - * @returns {CachedContainer} - * @todo define `CachedContainer` - */ - protected _drawOcclusionMask(): PIXI.Container; - - override deactivate(): this; - - override tearDown(): Promise; - - override getZIndex(): number; - - override getDocuments(): TileDocument[]; - - /** - * Refresh the display of tiles on the Foreground Layer depending on Token occlusion. - */ - refresh(): void; - - /** Update occlusion for all tiles on the foreground layer */ - updateOcclusion(): void; - - /** - * Draw the container which caches token-based occlusion shapes - * @param tokens The set of currently observed tokens - */ - protected _drawOcclusionShapes(tokens: Token[]): void; - - protected override _getDropData( - event: PIXI.InteractionEvent, - data: foundry.data.TileSource - ): Promise; -} diff --git a/types/foundry/client/pixi/placeables-layer/tiles-layer.d.ts b/types/foundry/client/pixi/placeables-layer/tiles-layer.d.ts index 8547e2ac2ba..4caf0b99439 100644 --- a/types/foundry/client/pixi/placeables-layer/tiles-layer.d.ts +++ b/types/foundry/client/pixi/placeables-layer/tiles-layer.d.ts @@ -1 +1,9 @@ -declare class TilesLayer extends PlaceablesLayer {} +/** + * A PlaceablesLayer designed for rendering the visual Scene for a specific vertical cross-section. + * @category - Canvas + * @todo fill in + */ + +declare class TilesLayer extends PlaceablesLayer { + static override documentName: "Tile"; +} diff --git a/types/foundry/client/pixi/placeables-layer/walls-layer.d.ts b/types/foundry/client/pixi/placeables-layer/walls-layer.d.ts index 1a5c38497e0..af2f49f9de8 100644 --- a/types/foundry/client/pixi/placeables-layer/walls-layer.d.ts +++ b/types/foundry/client/pixi/placeables-layer/walls-layer.d.ts @@ -25,7 +25,7 @@ declare global { protected _forceSnap: boolean; /** Track the most recently created or updated wall data for use with the clone tool */ - protected _cloneType: foundry.data.WallSource; + protected _cloneType: foundry.documents.WallSource; /** Reference the last interacted wall endpoint for the purposes of chaining */ last: { id: string | null; point: PointArray }; @@ -133,7 +133,7 @@ declare global { * This method helps to translate each tool into a default wall data configuration for that type * @param tool The active canvas tool */ - protected _getWallDataFromActiveTool(tool: string): Partial; + protected _getWallDataFromActiveTool(tool: string): Partial; /* -------------------------------------------- */ /* Event Listeners and Handlers */ diff --git a/types/foundry/client/roll.d.ts b/types/foundry/client/roll.d.ts index a63349202a7..a0d02b0bb85 100644 --- a/types/foundry/client/roll.d.ts +++ b/types/foundry/client/roll.d.ts @@ -355,17 +355,17 @@ declare global { * or the Object of prepared chatData otherwise. */ toMessage( - messageData: PreCreate | undefined, + messageData: PreCreate | undefined, { rollMode, create }: { rollMode?: RollMode | "roll"; create: false } - ): Promise; + ): Promise; toMessage( - messageData?: PreCreate, + messageData?: PreCreate, { rollMode, create }?: { rollMode?: RollMode | "roll"; create?: true } ): Promise; toMessage( - messageData?: PreCreate, + messageData?: PreCreate, { rollMode, create }?: { rollMode?: RollMode | "roll"; create?: boolean } - ): Promise; + ): Promise; /* -------------------------------------------- */ /* Interface Helpers */ diff --git a/types/foundry/client/ui/index.d.ts b/types/foundry/client/ui/index.d.ts index cc81c3fffc4..7801eae69b9 100644 --- a/types/foundry/client/ui/index.d.ts +++ b/types/foundry/client/ui/index.d.ts @@ -9,9 +9,9 @@ import "./tour"; declare global { interface FoundryUI< - TActor extends Actor, + TActor extends Actor, TActorDirectory extends ActorDirectory, - TItem extends Item, + TItem extends Item, TChatLog extends ChatLog, TCompendiumDirectory extends CompendiumDirectory > { diff --git a/types/foundry/common/abstract/data.d.ts b/types/foundry/common/abstract/data.d.ts index 337bdc27c2a..d51faaf43eb 100644 --- a/types/foundry/common/abstract/data.d.ts +++ b/types/foundry/common/abstract/data.d.ts @@ -5,176 +5,6 @@ declare global { module abstract { export import DataModel = AbstractDataModel.DataModel; export import _DataModel = AbstractDataModel._DataModel; - - /** - * A schema entry which describes a field of DocumentData - * @property type An object which defines the data type of this field - * @property required Is this field required to have an assigned value? Default is false. - * @property [nullable] Can the field be populated by a null value? Default is true. - * @property [default] A static default value or a function which assigns a default value - * @property [clean] An optional cleaning function which sanitizes input data to this field - * @property [validate] A function which asserts that the value of this field is valid - * @property [validationError] An error message which is displayed if validation fails - * @property [isCollection] Is the field an embedded Document collection? - */ - interface DocumentField { - type: object; - required: boolean; - nullable?: boolean; - default?: unknown; - clean?: Function; - validate?: (data: any) => boolean; - validationError?: string; - isCollection?: boolean; - } - - /** The schema of a Document */ - type DocumentSchema = Record; - - type DocumentSource = object; - - /** - * An abstract pattern for a data object which is contained within every type of Document. - * @param [data={}] Initial data used to construct the data object - * @param [document] The document to which this data object belongs - */ - abstract class DocumentData { - constructor(data?: DocumentSource, document?: TDocument | null); - - /** An immutable reverse-reference to the Document to which this data belongs, possibly null. */ - readonly document: TDocument | null; - - /** The source data object. The contents of this object can be updated, but the object itself may not be replaced. */ - readonly _source: DocumentSource; - - /** - * The primary identifier for the Document to which this data object applies. - * This identifier is unique within the parent collection which contains the Document. - */ - _id: string /* | null */; - - /** - * Define the data schema for documents of this type. - * The schema is populated the first time it is accessed and cached for future reuse. - */ - static defineSchema(): DocumentSchema; - - /** Define the data schema for documents of this type. */ - static get schema(): DocumentSchema; - - static _schema?: DocumentSchema; - - /** - * Define the data schema for this document instance. - * @alias {DocumentData.schema} - */ - get schema(): DocumentSchema; - - /* ---------------------------------------- */ - /* Data Initialization and Validation */ - /* ---------------------------------------- */ - - /** Initialize the source data object in-place */ - protected _initializeSource(data: object): this["_source"]; - - /** - * Get the default value for a schema field, conditional on the provided data - * @param field The configured data field - * @param data The provided data object - * @returns The default value for the field - */ - protected static _getFieldDefaultValue(field: DocumentField, data: unknown): unknown; - - /** Initialize the instance by copying data from the source object to instance attributes. */ - protected _initialize(): void; - - /** - * Initialize the value for a given data type - * @param type The type of the data field - * @param value The un-initialized value - * @returns The initialized value - */ - protected _initializeType(type: string, value: unknown): unknown; - - /** - * Validate the data contained in the document to check for type and content - * This function throws an error if data within the document is not valid - * - * @param options Optional parameters which customize how validation occurs. - * @param [options.changes] Only validate the keys of an object that was changed. - * @param [options.children] Validate the data of child embedded documents? Default is true. - * @param [options.clean] Apply field-specific cleaning functions to the provided value. - * @param [options.replace] Replace any invalid values with valid defaults? Default is false. - * @param [options.strict] If strict, will throw errors for any invalid data. Default is false. - * @return An indicator for whether or not the document contains valid data - */ - validate({ - changes, - children, - clean, - replace, - strict, - }?: { - changes?: boolean; - children?: boolean; - clean?: boolean; - replace?: boolean; - strict?: boolean; - }): boolean; - - /** - * Jointly validate the overall document after each field has been individually validated. - * Throw an Error if any issue is encountered. - */ - protected _validateDocument(): void; - - /** Reset the state of this data instance back to mirror the contained source data, erasing any changes. */ - reset(): boolean; - - /** - * Update the data by applying a new data object. Data is compared against and merged with the existing data. - * Updating data which already exists is strict - it must pass validation or else the update is rejected. - * An object is returned which documents the set of changes which were applied to the original data. - * @see utils.mergeObject - * @param data New values with which to update the Data object - * @param options Options which determine how the new data is merged - * @returns The changed keys and values which are different than the previous data - */ - update(data?: DocumentUpdateData, options?: DocumentModificationContext): DeepPartial; - - /** - * Copy and transform the DocumentData into a plain object. - * Draw the values of the extracted object from the data source (by default) otherwise from its transformed values. - * @param [source=true] Draw values from the underlying data source rather than transformed values - * @returns The extracted primitive object - */ - toObject(this: D, source?: true): D["_source"]; - toObject(this: D, source: false): RawObject; - toObject(source?: boolean): D["_source"] | RawObject; - - /** - * Extract the source data for the DocumentData into a simple object format that can be serialized. - * @returns The document source data expressed as a plain object - */ - toJSON(): this["_source"]; - - /** - * Create a DocumentData instance using a provided serialized JSON string. - * @param json Serialized document data in string format - * @returns A constructed data instance - */ - static fromJSON(this: ConstructorOf, json: string): T; - } } } - - type RawObject = { - [P in keyof T["_source"]]: T[P] extends foundry.abstract.EmbeddedCollection - ? RawObject[] - : T[P] extends foundry.abstract.DocumentData - ? RawObject - : T[P] extends foundry.abstract.DocumentData[] - ? RawObject[] - : T[P]; - }; } diff --git a/types/foundry/common/abstract/document.d.ts b/types/foundry/common/abstract/document.d.ts index 1a8e44495b8..0f757842d13 100644 --- a/types/foundry/common/abstract/document.d.ts +++ b/types/foundry/common/abstract/document.d.ts @@ -4,19 +4,18 @@ declare global { module foundry { module abstract { /** The abstract base interface for all Document types. */ - abstract class Document { - constructor(data: PreCreate, context?: DocumentConstructionContext); + abstract class Document { + constructor(data: object, context?: DocumentConstructionContext); + + _id: string | null; /** An immutable reverse-reference to the parent Document to which this embedded Document belongs. */ - readonly parent: Document | null; + readonly parent: TParent; /** An immutable reference to a containing Compendium collection to which this Document belongs. */ readonly pack: string | null; - /** The base data object for this Document which persists both the original source and any derived data. */ - readonly data: DocumentData; - - _source: this["data"]["_source"]; + _source: object; /** Perform one-time initialization tasks which only occur when the Document is first constructed. */ protected _initialize(): void; @@ -31,7 +30,7 @@ declare global { */ protected _initializeSource( data: Record, - options?: DocumentConstructionContext + options?: DocumentConstructionContext ): this["_source"]; /** @@ -43,12 +42,6 @@ declare global { /* Configuration */ /* -------------------------------------------- */ - /** - * Every document must define an object which represents its data schema. - * This must be a subclass of the DocumentData interface. - */ - static get schema(): ConstructorOf; - /** Default metadata which applies to each instance of this Document type. */ static get metadata(): DocumentMetadata; @@ -99,7 +92,7 @@ declare global { * @param source The candidate source data from which the model will be constructed * @returns Migrated source data, if necessary */ - static migrateData(source: TSource): TSource; + static migrateData(source: TSource): TSource; /** * Update the DataModel locally by applying an object of changes to its source data. @@ -113,7 +106,7 @@ declare global { */ updateSource( data?: DocumentUpdateData, - options?: DocumentModificationContext + options?: DocumentSourceUpdateContext ): DeepPartial; /** @@ -129,11 +122,8 @@ declare global { data: DocumentUpdateData | undefined, options: DocumentCloneOptions & { save: true } ): Promise; - clone( - data?: DocumentUpdateData, - options?: DocumentCloneOptions & { save?: false } - ): T; - clone(data?: DocumentUpdateData, options?: DocumentCloneOptions): T | Promise; + clone(data?: DocumentUpdateData, options?: DocumentCloneOptions & { save?: false }): this; + clone(data?: DocumentUpdateData, options?: DocumentCloneOptions): this | Promise; /** * Get the permission level that a specific User has over this Document, a value in CONST.ENTITY_PERMISSIONS. @@ -194,11 +184,12 @@ declare global { * const data = [{name: "Compendium Actor", type: "character", img: "path/to/profile.jpg"}]; * const created = await Actor.createDocuments(data, {pack: "mymodule.mypack"}); */ - static createDocuments( - this: ConstructorOf, - data?: (T | PreCreate)[], - context?: DocumentModificationContext - ): Promise; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + static createDocuments>( + this: ConstructorOf, + data?: (TDocument | PreCreate)[], + context?: DocumentModificationContext + ): Promise; /** * Update multiple Document instances using provided differential data. @@ -228,7 +219,7 @@ declare global { static updateDocuments( this: ConstructorOf, updates?: DocumentUpdateData[], - context?: DocumentModificationContext + context?: DocumentModificationContext ): Promise; /** @@ -259,11 +250,11 @@ declare global { * const deleted = await Actor.deleteDocuments([actor.id], {pack: "mymodule.mypack"}); */ // eslint-disable-next-line @typescript-eslint/no-explicit-any - static deleteDocuments>( - this: T, + static deleteDocuments>( + this: ConstructorOf, ids?: string[], - context?: DocumentModificationContext - ): Promise[]>; + context?: DocumentModificationContext + ): Promise; /** * Create a new Document using provided input data, saving it to the database. @@ -285,21 +276,21 @@ declare global { * const data = [{name: "Special Sword", type: "weapon"}]; * const created = await Item.create(data, {pack: "mymodule.mypack"}); */ - static create( - this: ConstructorOf, - data: PreCreate, - context?: DocumentModificationContext - ): Promise; - static create( - this: ConstructorOf, - data: PreCreate[], - context?: DocumentModificationContext - ): Promise; - static create( - this: ConstructorOf, - data: PreCreate | PreCreate[], - context?: DocumentModificationContext - ): Promise; + static create( + this: ConstructorOf, + data: PreCreate, + context?: DocumentModificationContext + ): Promise; + static create( + this: ConstructorOf, + data: PreCreate[], + context?: DocumentModificationContext + ): Promise; + static create( + this: ConstructorOf, + data: PreCreate | PreCreate[], + context?: DocumentModificationContext + ): Promise; /** * Update one or multiple existing entities using provided input data. @@ -321,7 +312,7 @@ declare global { * const data = [{_id: "12ekjf43kj2312ds", name: "New Name 1"}, {_id: "kj549dk48k34jk34", name: "New Name 2"}]}; * const updated = await Document.update(data); // Returns an Array of Entities, updated in the database */ - update(data: DocumentUpdateData, options?: DocumentModificationContext): Promise; + update(data: DocumentUpdateData, options?: DocumentModificationContext): Promise; /** * Delete the current Document. @@ -330,7 +321,7 @@ declare global { * @param context Options which customize the deletion workflow * @return The deleted Document */ - delete(context?: DocumentModificationContext): Promise; + delete(context?: DocumentModificationContext): Promise; /* -------------------------------------------- */ /* Embedded Operations */ @@ -341,7 +332,7 @@ declare global { * @param embeddedName The name of the embedded Document type * @return The Collection instance of embedded Documents of the requested type */ - getEmbeddedCollection(embeddedName: string): abstract.EmbeddedCollection; + getEmbeddedCollection(embeddedName: string): abstract.EmbeddedCollection>; /** * Get an embedded document by it's id from a named collection in the parent document. @@ -373,8 +364,8 @@ declare global { */ createEmbeddedDocuments( embeddedName: string, - data: PreCreate[], - context?: DocumentModificationContext + data: PreCreate[], + context?: DocumentModificationContext ): Promise; /** @@ -391,7 +382,7 @@ declare global { updateEmbeddedDocuments( embeddedName: string, updateData: EmbeddedDocumentUpdateData[], - context?: DocumentModificationContext + context?: DocumentUpdateContext ): Promise; /** @@ -405,7 +396,7 @@ declare global { deleteEmbeddedDocuments( embeddedName: string, dataId: string[], - context?: DocumentModificationContext + context?: DocumentModificationContext ): Promise; /* -------------------------------------------- */ @@ -463,7 +454,7 @@ declare global { */ protected _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: documents.BaseUser ): Promise; @@ -476,7 +467,7 @@ declare global { */ protected _preUpdate( changed: DeepPartial, - options: DocumentUpdateContext, + options: DocumentUpdateContext, user: documents.BaseUser ): Promise; @@ -487,7 +478,7 @@ declare global { * @param user The User requesting the document deletion */ protected _preDelete( - options: DocumentModificationContext, + options: DocumentModificationContext, user: documents.BaseUser ): Promise; @@ -499,7 +490,7 @@ declare global { */ protected _onCreate( data: this["_source"], - options: DocumentModificationContext, + options: DocumentModificationContext, userId: string ): void; @@ -512,7 +503,7 @@ declare global { */ protected _onUpdate( changed: DeepPartial, - options: DocumentUpdateContext, + options: DocumentUpdateContext, userId: string ): void; @@ -522,7 +513,7 @@ declare global { * @param options Additional options which modify the deletion request * @param userId The ID of the User requesting the document deletion */ - protected _onDelete(options: DocumentModificationContext, userId: string): void; + protected _onDelete(options: DocumentModificationContext, userId: string): void; /** * Perform follow-up operations when a set of Documents of this type are created. @@ -531,7 +522,10 @@ declare global { * @param documents The Document instances which were created * @param context The context for the modification operation */ - protected static _onCreateDocuments(documents: Document[], context: DocumentModificationContext): void; + protected static _onCreateDocuments( + documents: Document[], + context: DocumentModificationContext + ): void; /** * Perform follow-up operations when a set of Documents of this type are updated. @@ -540,7 +534,10 @@ declare global { * @param documents The Document instances which were updated * @param context The context for the modification operation */ - protected static _onUpdateDocuments(documents: Document[], context: DocumentModificationContext): void; + protected static _onUpdateDocuments( + documents: Document[], + context: DocumentModificationContext + ): void; /** * Perform follow-up operations when a set of Documents of this type are deleted. @@ -549,7 +546,10 @@ declare global { * @param documents The Document instances which were deleted * @param context The context for the modification operation */ - protected static _onDeleteDocuments(documents: Document[], context: DocumentModificationContext): void; + protected static _onDeleteDocuments( + documents: Document[], + context: DocumentModificationContext + ): void; /* ---------------------------------------- */ /* Serialization and Storage */ @@ -563,13 +563,13 @@ declare global { * @returns The extracted primitive object */ toObject(source?: true): this["_source"]; - toObject(source: false): RawObject; - toObject(source?: boolean): this["_source"] | RawObject; + toObject(source: false): RawObject; + toObject(source?: boolean): this["_source"] | RawObject; /** * Serializing an Document should simply serialize its inner data, not the entire instance */ - toJSON(): RawObject; + toJSON(): RawObject; } type MetadataPermission = @@ -602,14 +602,16 @@ declare global { [key: string]: unknown; } + type DocumentSourceUpdateContext = Omit, "parent">; + interface DocumentCloneOptions extends Omit, "parent"> { save?: boolean; keepId?: boolean; } - interface DocumentModificationContext { + interface DocumentModificationContext { /** A parent Document within which these Documents should be embedded */ - parent?: T["parent"]; + parent?: TParent; /** Block the dispatch of preCreate hooks for this operation */ noHook?: boolean; /** A Compendium pack identifier within which the Documents should be modified */ @@ -634,20 +636,16 @@ declare global { deleteAll?: boolean; } - type DocumentUpdateContext = Omit< - DocumentModificationContext, + type DocumentUpdateContext = Omit< + DocumentModificationContext, "deleteAll" | "index" | "keepId" | "keepEmbeddedIds" | "temporary" >; - type Embedded = T & { - readonly parent: NonNullable; - }; - - type PreCreate = T extends { name: string; type: string } + type PreCreate = T extends { name: string; type: string } ? Omit, "name" | "type"> & { name: string; type: T["type"] } : DeepPartial; - type PreDocumentId = Omit & { _id: null }; + type PreDocumentId = Omit & { _id: null }; type DocumentUpdateData = | Partial @@ -662,4 +660,16 @@ declare global { } type DocumentFlags = Record | undefined>; + + type RawObject = { + [P in keyof T["_source"]]: T[P] extends foundry.abstract.EmbeddedCollection + ? RawObject[] + : T[P] extends foundry.abstract.Document + ? RawObject + : T[P] extends foundry.abstract.Document[] + ? RawObject[] + : T[P]; + }; } + +type _Document = foundry.abstract.Document<_Document | null>; diff --git a/types/foundry/common/abstract/embedded-collection.d.ts b/types/foundry/common/abstract/embedded-collection.d.ts index 2a8f5d5f5de..64f060de6ff 100644 --- a/types/foundry/common/abstract/embedded-collection.d.ts +++ b/types/foundry/common/abstract/embedded-collection.d.ts @@ -7,7 +7,7 @@ declare global { * Used for the specific task of containing embedded Document instances within a parent Document. * @param sourceArray The source data array for the collection in the parent Document data */ - class EmbeddedCollection extends utils.Collection> { + class EmbeddedCollection> extends utils.Collection { constructor( sourceArray: TDocument["_source"][], documentClass: { @@ -23,8 +23,8 @@ declare global { override delete(key: string, { modifySource }?: { modifySource?: boolean }): boolean; toObject(source?: T): TDocument["_source"][]; - toObject(source: T): RawObject[]; - toObject(source?: T): TDocument["_source"][] | RawObject[]; + toObject(source: T): RawObject[]; + toObject(source?: T): TDocument["_source"][] | RawObject[]; } } } diff --git a/types/foundry/common/abstract/index.d.ts b/types/foundry/common/abstract/index.d.ts index fffbba7a1ec..b45f8ba0c48 100644 --- a/types/foundry/common/abstract/index.d.ts +++ b/types/foundry/common/abstract/index.d.ts @@ -1,3 +1,2 @@ -import "./data"; import "./document"; import "./embedded-collection"; diff --git a/types/foundry/common/constants.d.mts b/types/foundry/common/constants.d.mts index 80c3d6fb4c3..8d536338442 100644 --- a/types/foundry/common/constants.d.mts +++ b/types/foundry/common/constants.d.mts @@ -615,7 +615,7 @@ export const UPLOADABLE_FILE_EXTENSIONS: typeof IMAGE_FILE_EXTENSIONS & * A list of MIME types which are treated as uploaded "media", which are allowed to overwrite existing files. * Any non-media MIME type is not allowed to replace an existing file. */ -export const MEDIA_MIME_TYPES: typeof UPLOADABLE_FILE_EXTENSIONS[keyof typeof UPLOADABLE_FILE_EXTENSIONS]; +export const MEDIA_MIME_TYPES: (typeof UPLOADABLE_FILE_EXTENSIONS)[keyof typeof UPLOADABLE_FILE_EXTENSIONS]; /** An enumeration of file type categories which can be selected */ export const FILE_CATEGORIES: { @@ -657,41 +657,42 @@ declare global { defaultRole: UserRole; } + type ActiveEffectChangeMode = (typeof CONST.ACTIVE_EFFECT_MODES)[keyof typeof CONST.ACTIVE_EFFECT_MODES]; type AudioFileExtension = keyof typeof AUDIO_FILE_EXTENSIONS; - type CanvasPerformanceMode = typeof CANVAS_PERFORMANCE_MODES[keyof typeof CANVAS_PERFORMANCE_MODES]; - type ChatMessageType = typeof CONST.CHAT_MESSAGE_TYPES[keyof typeof CONST.CHAT_MESSAGE_TYPES]; - type CompatibilityMode = typeof CONST.COMPATIBILITY_MODES[keyof typeof CONST.COMPATIBILITY_MODES]; - type DocumentOwnershipLevel = typeof DOCUMENT_OWNERSHIP_LEVELS[DocumentOwnershipString]; + type CanvasPerformanceMode = (typeof CANVAS_PERFORMANCE_MODES)[keyof typeof CANVAS_PERFORMANCE_MODES]; + type ChatMessageType = (typeof CONST.CHAT_MESSAGE_TYPES)[keyof typeof CONST.CHAT_MESSAGE_TYPES]; + type CompatibilityMode = (typeof CONST.COMPATIBILITY_MODES)[keyof typeof CONST.COMPATIBILITY_MODES]; + type DocumentOwnershipLevel = (typeof DOCUMENT_OWNERSHIP_LEVELS)[DocumentOwnershipString]; type DocumentOwnershipString = keyof typeof DOCUMENT_OWNERSHIP_LEVELS; - type DrawingFillType = typeof DRAWING_FILL_TYPES[keyof typeof DRAWING_FILL_TYPES]; + type DrawingFillType = (typeof DRAWING_FILL_TYPES)[keyof typeof DRAWING_FILL_TYPES]; type FileCategory = keyof typeof FILE_CATEGORIES; type FileExtension = keyof typeof UPLOADABLE_FILE_EXTENSIONS; - type FolderDocumentType = typeof FOLDER_DOCUMENT_TYPES[number]; - type GridType = typeof GRID_TYPES[keyof typeof GRID_TYPES]; + type FolderDocumentType = (typeof FOLDER_DOCUMENT_TYPES)[number]; + type GridType = (typeof GRID_TYPES)[keyof typeof GRID_TYPES]; type ImageFileExtension = keyof typeof IMAGE_FILE_EXTENSIONS; - type JournalEntryPageFormat = typeof JOURNAL_ENTRY_PAGE_FORMATS[keyof typeof JOURNAL_ENTRY_PAGE_FORMATS]; - type MacroScope = typeof MACRO_SCOPES[number]; - type MacroType = typeof MACRO_TYPES[keyof typeof MACRO_TYPES]; - type MeasuredTemplateType = typeof MEASURED_TEMPLATE_TYPES[keyof typeof MEASURED_TEMPLATE_TYPES]; - type PackageType = typeof PACKAGE_TYPES[number]; - type PlaylistMode = typeof PLAYLIST_MODES[keyof typeof PLAYLIST_MODES]; - type PlaylistSortMode = typeof PLAYLIST_SORT_MODES[keyof typeof PLAYLIST_SORT_MODES]; - type RollMode = typeof CONST.DICE_ROLL_MODES[keyof typeof CONST.DICE_ROLL_MODES]; - type TableResultType = typeof TABLE_RESULT_TYPES[keyof typeof TABLE_RESULT_TYPES]; - type TextAnchorPoint = typeof TEXT_ANCHOR_POINTS[keyof typeof TEXT_ANCHOR_POINTS]; - type TileOcclusionMode = typeof TILE_OCCLUSION_MODES[keyof typeof TILE_OCCLUSION_MODES]; - type TokenDisplayMode = typeof TOKEN_DISPLAY_MODES[keyof typeof TOKEN_DISPLAY_MODES]; - type TokenDisposition = typeof TOKEN_DISPOSITIONS[keyof typeof TOKEN_DISPOSITIONS]; + type JournalEntryPageFormat = (typeof JOURNAL_ENTRY_PAGE_FORMATS)[keyof typeof JOURNAL_ENTRY_PAGE_FORMATS]; + type MacroScope = (typeof MACRO_SCOPES)[number]; + type MacroType = (typeof MACRO_TYPES)[keyof typeof MACRO_TYPES]; + type MeasuredTemplateType = (typeof MEASURED_TEMPLATE_TYPES)[keyof typeof MEASURED_TEMPLATE_TYPES]; + type PackageType = (typeof PACKAGE_TYPES)[number]; + type PlaylistMode = (typeof PLAYLIST_MODES)[keyof typeof PLAYLIST_MODES]; + type PlaylistSortMode = (typeof PLAYLIST_SORT_MODES)[keyof typeof PLAYLIST_SORT_MODES]; + type RollMode = (typeof CONST.DICE_ROLL_MODES)[keyof typeof CONST.DICE_ROLL_MODES]; + type TableResultType = (typeof TABLE_RESULT_TYPES)[keyof typeof TABLE_RESULT_TYPES]; + type TextAnchorPoint = (typeof TEXT_ANCHOR_POINTS)[keyof typeof TEXT_ANCHOR_POINTS]; + type TileOcclusionMode = (typeof TILE_OCCLUSION_MODES)[keyof typeof TILE_OCCLUSION_MODES]; + type TokenDisplayMode = (typeof TOKEN_DISPLAY_MODES)[keyof typeof TOKEN_DISPLAY_MODES]; + type TokenDisposition = (typeof TOKEN_DISPOSITIONS)[keyof typeof TOKEN_DISPOSITIONS]; type UserAction = "create" | "update" | "delete"; type UserPermissionString = keyof typeof USER_PERMISSIONS; type UserRole = keyof typeof USER_ROLE_NAMES; type UserRoleName = keyof typeof USER_ROLES; type VideoFileExtension = keyof typeof VIDEO_FILE_EXTENSIONS; - type WallDirection = typeof WALL_DIRECTIONS[keyof typeof WALL_DIRECTIONS]; - type WallDoorState = typeof WALL_DOOR_STATES[keyof typeof WALL_DOOR_STATES]; - type WallDoorType = typeof WALL_DOOR_TYPES[keyof typeof WALL_DOOR_TYPES]; - type WallMovementType = typeof WALL_MOVEMENT_TYPES[keyof typeof WALL_MOVEMENT_TYPES]; - type WallRestrictionType = typeof WALL_RESTRICTION_TYPES[number]; - type WallSenseType = typeof WALL_SENSE_TYPES[keyof typeof WALL_SENSE_TYPES]; + type WallDirection = (typeof WALL_DIRECTIONS)[keyof typeof WALL_DIRECTIONS]; + type WallDoorState = (typeof WALL_DOOR_STATES)[keyof typeof WALL_DOOR_STATES]; + type WallDoorType = (typeof WALL_DOOR_TYPES)[keyof typeof WALL_DOOR_TYPES]; + type WallMovementType = (typeof WALL_MOVEMENT_TYPES)[keyof typeof WALL_MOVEMENT_TYPES]; + type WallRestrictionType = (typeof WALL_RESTRICTION_TYPES)[number]; + type WallSenseType = (typeof WALL_SENSE_TYPES)[keyof typeof WALL_SENSE_TYPES]; type DrawingShapeType = "r" | "e" | "t" | "p" | "f"; } diff --git a/types/foundry/common/data/data/active-effect-data.d.ts b/types/foundry/common/data/data/active-effect-data.d.ts deleted file mode 100644 index 6325afe99f7..00000000000 --- a/types/foundry/common/data/data/active-effect-data.d.ts +++ /dev/null @@ -1,49 +0,0 @@ -declare module foundry { - module data { - /** - * @property _id The EmbeddedEntity id of the Active Effect - * @property label The label which describes this effect - * @property [disabled] Is this effect currently disabled? - * @property [icon] An image icon path for this effect - * @property [tint] A hex color string to tint the effect icon - * @property [origin] The UUID of an Entity or EmbeddedEntity which was the source of this effect - * @property [transfer] Should this effect transfer automatically to an Actor when its Item becomes owned? - * @property flags Additional key/value flags - */ - interface ActiveEffectSource { - _id: string; - label: string; - duration: EffectDurationSource; - changes: EffectChangeSource[]; - disabled: boolean; - icon: ImageFilePath; - tint: string; - origin: string | undefined; - transfer: boolean; - flags: Record; - } - - class ActiveEffectData< - TDocument extends documents.BaseActiveEffect = documents.BaseActiveEffect - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - /** @property duration The duration of the effect */ - duration: EffectDurationData; - - /** @property changes The changes applied by this effect */ - changes: EffectChangeData[]; - } - - interface ActiveEffectData extends Omit { - readonly _source: ActiveEffectSource; - } - } -} - -declare interface ActiveEffectDurationSummary { - type: "seconds" | "turns" | "none"; - duration: number; - remaining: number; - label: string; -} diff --git a/types/foundry/common/data/data/actor-data.d.ts b/types/foundry/common/data/data/actor-data.d.ts deleted file mode 100644 index 42a19a56c7c..00000000000 --- a/types/foundry/common/data/data/actor-data.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a Actor document. - * @see BaseActor - * - * @param data Initial data used to construct the data object - * @param [document] The document to which this data object belongs - * - * @property _id The _id which uniquely identifies this Actor document - * @property name The name of this Actor - * @property type An Actor subtype which configures the system data model applied - * @property [img] An image file path which provides the artwork for this Actor - * @property [data] The system data object which is defined by the system template.json model - * @property [token] Default Token settings which are used for Tokens created from this Actor - * @property items A Collection of Item embedded Documents - * @property effects A Collection of ActiveEffect embedded Documents - * @property folder The _id of a Folder which contains this Actor - * @property [sort] The numeric sort value which orders this Actor relative to its siblings - * @property [ownership] An object which configures user permissions to this Actor - * @property [flags={}] An object of optional key/value flags - */ - interface ActorSource< - TType extends string = string, - TSystemSource extends object = object, - TItemSource extends ItemSource = ItemSource - > { - _id: string; - name: string; - type: TType; - img: ImageFilePath; - system: TSystemSource; - prototypeToken: PrototypeTokenSource; - items: TItemSource[]; - effects: ActiveEffectSource[]; - folder: string | null; - sort: number; - ownership: Record; - flags: documents.ActorFlags; - } - } -} diff --git a/types/foundry/common/data/data/ambient-light-data.d.ts b/types/foundry/common/data/data/ambient-light-data.d.ts deleted file mode 100644 index 4a1009b09c8..00000000000 --- a/types/foundry/common/data/data/ambient-light-data.d.ts +++ /dev/null @@ -1,46 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a AmbientLight embedded document. - * - * @property _id The _id which uniquely identifies this BaseAmbientLight embedded document - * @property [x=0] The x-coordinate position of the origin of the light - * @property [y=0] The y-coordinate position of the origin of the light - * @property [rotation=0] The angle of rotation for the tile between 0 and 360 - * @property [walls=true] Whether or not this light source is constrained by Walls - * @property [vision=false] Whether or not this light source provides a source of vision - * @property config Light configuration data - * @property [hidden=false] Is the light source currently hidden? - * @property [flags={}] An object of optional key/value flags - */ - interface AmbientLightSource { - _id: string; - t: string; - x: number; - y: number; - rotation: number; - walls: boolean; - vision: boolean; - config: LightSource; - hidden: boolean; - flags: Record; - } - - class AmbientLightData< - TDocument extends documents.BaseAmbientLight = documents.BaseAmbientLight - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - lightAnimation: AnimationData; - - darkness: DarknessActivation; - } - - interface AmbientLightData - extends Omit { - readonly _source: AmbientLightSource; - - config: LightData; - } - } -} diff --git a/types/foundry/common/data/data/ambient-sound-data.d.ts b/types/foundry/common/data/data/ambient-sound-data.d.ts deleted file mode 100644 index 05772ba87a5..00000000000 --- a/types/foundry/common/data/data/ambient-sound-data.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a AmbientSound embedded document. - * @see BaseAmbientSound - * - * @param data Initial data used to construct the data object - * @param [document] The document to which this data object belongs - * - * @property _id The _id which uniquely identifies this AmbientSound document - * @property path The audio file path that is played by this sound - * @property [playing=false] Is this sound currently playing? - * @property [repeat=false] Does this sound loop? - * @property [volume=0.5] The audio volume of the sound, from 0 to 1 - * @property [flags={}] An object of optional key/value flags - */ - interface AmbientSoundSource { - _id: string; - type: string; - x: number; - y: number; - radius: number; - path: AudioFilePath; - repeat: boolean; - volume: number; - easing: boolean; - hidden: boolean; - darkness: DarknessActivationSource; - flags: Record; - } - - class AmbientSoundData< - TDocument extends documents.BaseAmbientSound = documents.BaseAmbientSound - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - darkness: DarknessActivation; - } - - interface AmbientSoundData extends Omit { - readonly _source: AmbientSoundSource; - } - } -} diff --git a/types/foundry/common/data/data/animation-data.d.ts b/types/foundry/common/data/data/animation-data.d.ts index 33138e4d612..6d464be3a1f 100644 --- a/types/foundry/common/data/data/animation-data.d.ts +++ b/types/foundry/common/data/data/animation-data.d.ts @@ -6,20 +6,10 @@ declare module foundry { * @property speed The speed of the animation, a number between 1 and 10 * @property intensity The intensity of the animation, a number between 1 and 10 */ - interface AnimationSource { + interface AnimationData { type: string; speed: number; intensity: number; } - - class AnimationData< - TDocument extends abstract.Document = abstract.Document - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface AnimationData extends AnimationSource { - readonly _source: AnimationSource; - } } } diff --git a/types/foundry/common/data/data/cards-data.d.ts b/types/foundry/common/data/data/cards-data.d.ts deleted file mode 100644 index 15fd70e3a71..00000000000 --- a/types/foundry/common/data/data/cards-data.d.ts +++ /dev/null @@ -1,50 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema of a stack of multiple Cards. - * Each stack can represent a Deck, a Hand, or a Pile. - */ - interface CardsSource<> { - /** The _id which uniquely identifies this stack of Cards document */ - _id: string; - /** The text name of this stack */ - name: string; - /** The type of this stack, in BaseCards.metadata.types */ - type: string; - /** A text description of this stack */ - description: string; - /** An image or video which is used to represent the stack of cards */ - img: VideoFilePath; - /** Game system data which is defined by the system template.json model */ - data: object; - /** A collection of Card documents which currently belong to this stack */ - cards: object; - /** The visible width of this stack */ - width: number; - /** The visible height of this stack */ - height: number; - /** The angle of rotation of this stack */ - rotation: string; - /** Whether or not to publicly display the number of cards in this stack */ - displayCount?: boolean; - /** The _id of a Folder which contains this document */ - folder?: string | null; - /** The sort order of this stack relative to others in its parent collection */ - sort: number; - /** An object which configures user permissions to this stack */ - ownership: Record; - /** An object of optional key/value flags */ - flags: Record>; - } - - interface CardsData - extends abstract.DocumentData { - /** The default icon used for a cards stack that does not have a custom image set */ - DEFAULT_ICON: ImageFilePath; - } - - interface CardsData extends CardsSource { - readonly _source: CardsSource; - } - } -} diff --git a/types/foundry/common/data/data/chat-message-data.d.ts b/types/foundry/common/data/data/chat-message-data.d.ts deleted file mode 100644 index 06b376753a8..00000000000 --- a/types/foundry/common/data/data/chat-message-data.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -declare module foundry { - module data { - interface ChatMessageSource { - _id: string; - type: ChatMessageType; - user: string; - timestamp: string; - flavor?: string; - content: string; - speaker: ChatSpeakerSource; - whisper: string[]; - blind: boolean; - rolls: (string | RollJSON)[]; - sound: AudioFilePath; - emote?: boolean; - flags: ChatMessageFlags; - } - - class ChatMessageData< - TDocument extends documents.BaseChatMessage = documents.BaseChatMessage - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface ChatMessageData extends ChatMessageSource { - readonly _source: ChatMessageSource; - - roll: string; - } - - type ChatMessageFlags = DocumentFlags & { - core?: { - canPopout?: boolean; - initiativeRoll?: boolean; - RollTable?: string; - }; - }; - } -} diff --git a/types/foundry/common/data/data/chat-speaker-data.d.ts b/types/foundry/common/data/data/chat-speaker-data.d.ts deleted file mode 100644 index b5f0ec9adf1..00000000000 --- a/types/foundry/common/data/data/chat-speaker-data.d.ts +++ /dev/null @@ -1,34 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for an embedded Chat Speaker object. - * @extends DocumentData - * @memberof data - * @see ChatMessageData - * - * @param data Initial data used to construct the data object - * @param [document] The document to which this data object belongs - * - * @property [scene] The _id of the Scene where this message was created - * @property [actor] The _id of the Actor who generated this message - * @property [token] The _id of the Token who generated this message - * @property [alias] An overridden alias name used instead of the Actor or Token name - */ - interface ChatSpeakerSource { - scene?: string | null; - actor?: string | null; - token?: string | null; - alias: string; - } - - class ChatSpeakerData< - TDocument extends documents.BaseChatMessage = documents.BaseChatMessage - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface ChatSpeakerData extends ChatSpeakerSource { - readonly _source: ChatSpeakerSource; - } - } -} diff --git a/types/foundry/common/data/data/combat-data.d.ts b/types/foundry/common/data/data/combat-data.d.ts deleted file mode 100644 index 077410616ca..00000000000 --- a/types/foundry/common/data/data/combat-data.d.ts +++ /dev/null @@ -1,40 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a Combat document. - * @property _id The _id which uniquely identifies this Combat document - * @property scene The _id of a Scene within which this Combat occurs - * @property combatants A Collection of Combatant embedded Documents - * @property [active=false] Is the Combat encounter currently active? - * @property [round=0] The current round of the Combat encounter - * @property [turn=0] The current turn in the Combat round - * @property [sort=0] The current sort order of this Combat relative to others in the same Scene - * @property [flags={}] An object of optional key/value flags - */ - interface CombatSource { - _id: string; - scene: string; - combatants: CombatantSource[]; - active: boolean; - round: number; - turn: number; - sort: number; - flags: Record>; - } - - class CombatData< - TDocument extends documents.BaseCombat = documents.BaseCombat, - TCombatant extends documents.BaseCombatant = documents.BaseCombatant - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - combatants: abstract.EmbeddedCollection; - } - - interface CombatData extends Omit { - readonly _source: CombatSource; - - readonly parent: null; - } - } -} diff --git a/types/foundry/common/data/data/combatant-data.d.ts b/types/foundry/common/data/data/combatant-data.d.ts deleted file mode 100644 index 8bd16b8c508..00000000000 --- a/types/foundry/common/data/data/combatant-data.d.ts +++ /dev/null @@ -1,35 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a Combat document. - * @property _id The _id which uniquely identifies this Combatant embedded document - * @property [tokenId] The _id of a Token associated with this Combatant - * @property [name] A customized name which replaces the name of the Token in the tracker - * @property [img] A customized image which replaces the Token image in the tracker - * @property [initiative] The initiative score for the Combatant which determines its turn order - * @property [hidden=false] Is this Combatant currently hidden? - * @property [defeated=false] Has this Combatant been defeated? - * @property [flags={}] An object of optional key/value flags - */ - interface CombatantSource { - _id: string; - actorId: string; - tokenId: string; - img: VideoFilePath; - initiative: number | null; - hidden: boolean; - defeated: boolean; - flags: Record; - } - - class CombatantData< - TDocument extends documents.BaseCombatant = documents.BaseCombatant - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface CombatantData extends CombatantSource { - readonly _source: CombatantSource; - } - } -} diff --git a/types/foundry/common/data/data/darkness-activation.d.ts b/types/foundry/common/data/data/darkness-activation.d.ts index dc7c51f542c..4e0a900e31e 100644 --- a/types/foundry/common/data/data/darkness-activation.d.ts +++ b/types/foundry/common/data/data/darkness-activation.d.ts @@ -5,19 +5,9 @@ declare module foundry { * @property [min=0] The minimum darkness level for which activation occurs * @property [max=1] The maximum darkness level for which activation occurs */ - interface DarknessActivationSource { + interface DarknessActivation { min: number; max: number; } - - class DarknessActivation extends abstract.DocumentData< - documents.BaseAmbientLight | documents.BaseAmbientSound - > {} - - interface DarknessActivation extends DarknessActivationSource { - readonly _source: DarknessActivationSource; - - readonly parent: null; - } } } diff --git a/types/foundry/common/data/data/drawing-data.d.ts b/types/foundry/common/data/data/drawing-data.d.ts deleted file mode 100644 index 15b86992a60..00000000000 --- a/types/foundry/common/data/data/drawing-data.d.ts +++ /dev/null @@ -1,74 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a Drawing embedded document. - * @see BaseDrawing - * - * @param data Initial data used to construct the data object - * @param [document] The embedded document to which this data object belongs - * - * @property t The value in CONST.DRAWING_TYPES which defines the geometry type of this drawing - * @property x The x-coordinate position of the top-left corner of the drawn shape - * @property y The y-coordinate position of the top-left corner of the drawn shape - * @property width The pixel width of the drawing figure - * @property height The pixel height of the drawing figure - * @property [rotation=0] The angle of rotation for the drawing figure - * @property [z=0] The z-index of this drawing relative to other siblings - * @property [points] An array of points [x,y] which define polygon vertices - * @property [bezierFactor=0] An amount of bezier smoothing applied, between 0 and 1 - * @property [fillType=0] The fill type of the drawing shape, a value from CONST.DRAWING_FILL_TYPES - * @property [fillColor] An optional color string with which to fill the drawing geometry - * @property [fillAlpha=0.5] The opacity of the fill applied to the drawing geometry - * @property [strokeWidth=8] The width in pixels of the boundary lines of the drawing geometry - * @property [strokeColor] The color of the boundary lines of the drawing geometry - * @property [strokeAlpha=1] The opacity of the boundary lines of the drawing geometry - * @property [texture] The path to a tiling image texture used to fill the drawing geometry - * @property [text] Optional text which is displayed overtop of the drawing - * @property [fontFamily=Signika] The font family used to display text within this drawing - * @property [fontSize=48] The font size used to display text within this drawing - * @property [textColor=#FFFFFF] The color of text displayed within this drawing - * @property [textAlpha=1] The opacity of text displayed within this drawing - * @property [hidden=false] Is the drawing currently hidden? - * @property [locked=false] Is the drawing currently locked? - */ - interface DrawingSource extends abstract.DocumentSource { - t: DrawingShapeType; - x: number; - y: number; - width: number; - height: number; - rotation?: number; - z?: number; - points?: [number, number][]; - bezierFactor?: number; - fillType?: number; - fillColor?: string; - fillAlpha?: number; - strokeWidth?: number; - strokeColor?: number; - strokeAlpha?: number; - texture?: string; - text?: string; - fontFamily?: string; - fontSize?: number; - textColor?: string; - textAlpha?: number; - hidden?: boolean; - locked?: boolean; - } - - class DrawingData< - TDocument extends documents.BaseDrawing = documents.BaseDrawing - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - protected override _initialize(): void; - - protected override _validateDocument(): void; - } - - interface DrawingData extends DrawingSource { - readonly _source: DrawingSource; - } - } -} diff --git a/types/foundry/common/data/data/effect-change-data.d.ts b/types/foundry/common/data/data/effect-change-data.d.ts deleted file mode 100644 index ea7b19f345a..00000000000 --- a/types/foundry/common/data/data/effect-change-data.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -declare module foundry { - module data { - /** - * An embedded data structure which defines the structure of a change applied by an ActiveEffect. - * @property key The attribute path in the Actor or Item data which the change modifies - * @property value The value of the change effect - * @property mode The modification mode with which the change is applied - * @property priority The priority level with which this change is applied - */ - interface EffectChangeSource { - key: string; - value: string; - mode: ActiveEffectChangeMode; - priority: number; - } - - class EffectChangeData< - TDocument extends documents.BaseActiveEffect = documents.BaseActiveEffect - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface EffectChangeData extends EffectChangeSource { - readonly _source: EffectDurationSource; - } - } -} - -declare type ActiveEffectChangeMode = (typeof CONST.ACTIVE_EFFECT_MODES)[keyof typeof CONST.ACTIVE_EFFECT_MODES]; diff --git a/types/foundry/common/data/data/effect-duration-data.d.ts b/types/foundry/common/data/data/effect-duration-data.d.ts deleted file mode 100644 index 98c65ab0f35..00000000000 --- a/types/foundry/common/data/data/effect-duration-data.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -declare module foundry { - module data { - /** - * An embedded data structure which tracks the duration of an ActiveEffect. - * @property startTime The world time when the active effect first started - * @property [seconds] The maximum duration of the effect, in seconds - * @property [combat] The _id of the CombatEncounter in which the effect first started - * @property [rounds] The maximum duration of the effect, in combat rounds - * @property [turns] The maximum duration of the effect, in combat turns - * @property [startRound] The round of the CombatEncounter in which the effect first started - * @property [startTurn] The turn of the CombatEncounter in which the effect first started - */ - interface EffectDurationSource { - startTime: number; - seconds: number | undefined; - combat?: string; - rounds: number | undefined; - turns: number | undefined; - startRound: number | null; - startTurn: number | null; - } - - class EffectDurationData< - TDocument extends documents.BaseActiveEffect = documents.BaseActiveEffect - > extends abstract.DocumentData {} - - interface EffectDurationData extends EffectDurationSource { - readonly _source: EffectDurationSource; - - /** @todo uncomment when prettier is updated to support typescript 4.3 */ - // get schema(): ReturnType; - } - - namespace EffectDurationData { - const schema: ReturnType<(typeof EffectDurationData)["defineSchema"]>; - } - } -} diff --git a/types/foundry/common/data/data/fog-exploration-data.d.ts b/types/foundry/common/data/data/fog-exploration-data.d.ts deleted file mode 100644 index a5f6ff99936..00000000000 --- a/types/foundry/common/data/data/fog-exploration-data.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a FogExploration document. - * @property _id The _id which uniquely identifies this FogExploration document - * @property scene The _id of the Scene document to which this fog applies - * @property user The _id of the User document to which this fog applies - * @property explored The base64 png image of the explored fog polygon - * @property positions The object of scene positions which have been explored at a certain vision radius - * @property timestamp The timestamp at which this fog exploration was last updated - */ - interface FogExplorationSource { - _id: string; - scene: string; - user: string; - explored: string; - position: unknown; - timestamp: number; - } - - class FogExplorationData< - TDocument extends documents.BaseFogExploration = documents.BaseFogExploration - > extends abstract.DocumentData {} - - interface FogExplorationData extends FogExplorationSource { - readonly _source: FogExplorationSource; - } - } -} diff --git a/types/foundry/common/data/data/folder-data.d.ts b/types/foundry/common/data/data/folder-data.d.ts deleted file mode 100644 index 621e88b1ef3..00000000000 --- a/types/foundry/common/data/data/folder-data.d.ts +++ /dev/null @@ -1,43 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a Folder document. - * - * @param data Initial data used to construct the data object - * @param [document] The document to which this data object belongs - * - * @property _id The _id which uniquely identifies this Folder document - * @property name The name of this Folder - * @property type The document type which this Folder contains, from CONST.FOLDER_DOCUMENT_TYPES - * @property [description] An HTML description of the contents of this folder - * @property [parent] The _id of a parent Folder which contains this Folder - * @property [sorting=a] The sorting mode used to organize documents within this Folder, in ["a", "m"] - * @property [sort] The numeric sort value which orders this Folder relative to its siblings - * @property [color] A color string used for the background color of this Folder - * @property [flags={}] An object of optional key/value flags - */ - interface FolderSource extends abstract.DocumentSource { - _id: string; - name: string; - type: FolderDocumentType; - description: string; - parent: string | null; - sorting: "a" | "m"; - sort: number; - color: HexColorString; - flags: Record; - } - - class FolderData< - TDocument extends documents.BaseFolder = documents.BaseFolder - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - static SORTING_MODES: ["a", "m"]; - } - - interface FolderData extends FolderSource { - readonly _source: FolderSource; - } - } -} diff --git a/types/foundry/common/data/data/index.d.ts b/types/foundry/common/data/data/index.d.ts index 5da1d4e683e..8c2c26acb5a 100644 --- a/types/foundry/common/data/data/index.d.ts +++ b/types/foundry/common/data/data/index.d.ts @@ -1,33 +1,7 @@ -import "./active-effect-data"; -import "./actor-data"; -import "./ambient-light-data"; -import "./ambient-sound-data"; import "./animation-data"; -import "./cards-data"; -import "./chat-message-data"; -import "./chat-speaker-data"; -import "./combat-data"; -import "./combatant-data"; import "./darkness-activation"; -import "./drawing-data"; -import "./effect-change-data"; -import "./effect-duration-data"; -import "./fog-exploration-data"; -import "./folder-data"; -import "./item-data"; import "./light-data"; -import "./macro-data"; -import "./measured-template-data"; -import "./note-data"; -import "./playlist-data"; -import "./playlist-sound-data"; import "./prototype-token-data"; -import "./roll-table-data"; -import "./scene-data"; -import "./table-result-data"; -import "./tile-data"; +import "./texture-data"; import "./tile-occlusion"; -import "./token-bar-data"; -import "./token-data"; import "./video-data"; -import "./wall-data"; diff --git a/types/foundry/common/data/data/item-data.d.ts b/types/foundry/common/data/data/item-data.d.ts deleted file mode 100644 index b31041f4c8f..00000000000 --- a/types/foundry/common/data/data/item-data.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a Item document. - * @see BaseItem - * - * @param data Initial data used to construct the data object - * @param [document] The document to which this data object belongs - * - * @property _id The _id which uniquely identifies this Item document - * @property name The name of this Item - * @property type An Item subtype which configures the system data model applied - * @property [img] An image file path which provides the artwork for this Item - * @property [data] The system data object which is defined by the system template.json model - * @property folder The _id of a Folder which contains this Item - * @property [sort] The numeric sort value which orders this Item relative to its siblings - * @property [ownership] An object which configures user permissions to this Item - * @property [flags={}] An object of optional key/value flags - */ - interface ItemSource { - _id: string; - name: string; - type: TType; - img: ImageFilePath; - system: TSystemSource; - effects: ActiveEffectSource[]; - folder?: string | null; - sort: number; - ownership: Record; - flags: documents.ItemFlags; - } - } -} diff --git a/types/foundry/common/data/data/light-data.d.ts b/types/foundry/common/data/data/light-data.d.ts index faa67d223b4..21eb36b7f2c 100644 --- a/types/foundry/common/data/data/light-data.d.ts +++ b/types/foundry/common/data/data/light-data.d.ts @@ -1,65 +1,72 @@ -declare module foundry { - module data { - /** - * A reusable document structure for the internal data used to render the appearance of a light source. - * This is re-used by both the AmbientLightData and TokenData classes. - * - * @property alpha An opacity for the emitted light, if any - * @property animation An animation configuration for the source - * @property angle The angle of emission for this point source - * @property bright The allowed radius of bright vision or illumination - * @property color A tint color for the emitted light, if any - * @property coloration The coloration technique applied in the shader - * @property contrast The amount of contrast this light applies to the background texture - * @property darkness A darkness range (min and max) for which the source should be active - * @property dim The allowed radius of dim vision or illumination - * @property invertColor Does this source invert the color of the background texture? - * @property gradual Fade the difference between bright, dim, and dark gradually? - * @property luminosity The luminosity applied in the shader - * @property saturation The amount of color saturation this light applies to the background texture - * @property shadows The depth of shadows this light applies to the background texture - */ - interface LightSource { - _id: string; - alpha: number; - animation: object; - angle: number; - bright: number; - color: string; - coloration: number; - contrast: number; - darkness: { min: number; max: number }; - dim: number; - invertColor: boolean; - gradual: boolean; - luminosity: number; - saturation: number; - shadows: number; - } - - class LightData< - TDocument extends documents.BaseAmbientLight | documents.BaseToken = - | documents.BaseAmbientLight - | documents.BaseToken - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; +import { DataModel } from "../../abstract/data.mjs"; +import { + AlphaField, + AngleField, + BooleanField, + ColorField, + ModelPropsFromSchema, + NumberField, + SchemaField, + StringField, +} from "../fields.mjs"; - /** A reusable field definition for uniform fields used by LightData */ - static LIGHT_UNIFORM_FIELD: { - type: typeof Number; - required: true; - default: number; - validate: (n: unknown) => boolean; - validationError: string; - }; +declare global { + module foundry { + module data { + /** + * A reusable document structure for the internal data used to render the appearance of a light source. + * This is re-used by both the AmbientLightData and TokenData classes. + * + * @property alpha An opacity for the emitted light, if any + * @property animation An animation configuration for the source + * @property angle The angle of emission for this point source + * @property bright The allowed radius of bright vision or illumination + * @property color A tint color for the emitted light, if any + * @property coloration The coloration technique applied in the shader + * @property contrast The amount of contrast this light applies to the background texture + * @property darkness A darkness range (min and max) for which the source should be active + * @property dim The allowed radius of dim vision or illumination + * @property invertColor Does this source invert the color of the background texture? + * @property gradual Fade the difference between bright, dim, and dark gradually? + * @property luminosity The luminosity applied in the shader + * @property saturation The amount of color saturation this light applies to the background texture + * @property shadows The depth of shadows this light applies to the background texture + */ + class LightData extends DataModel { + static override defineSchema(): LightDataSchema; - protected override _initializeSource(data: object): this["_source"]; + static override migrateData(source: TSource): TSource; + } - protected override _initialize(): void; - } + interface LightData + extends DataModel, + ModelPropsFromSchema {} - interface LightData extends LightSource { - readonly _source: LightSource; + type LightSource = SourceFromSchema; } } } + +type LightDataSchema = { + alpha: AlphaField; + angle: AngleField; + bright: NumberField; + color: ColorField; + coloration: NumberField; + dim: NumberField; + attenuation: NumberField; + luminosity: NumberField; + saturation: NumberField; + constrast: NumberField; + shadows: NumberField; + animation: SchemaField<{ + type: StringField; + speed: NumberField; + intensity: NumberField; + reverse: BooleanField; + }>; + darkness: SchemaField<{ + min: AlphaField; + speed: AlphaField; + }>; +}; diff --git a/types/foundry/common/data/data/macro-data.d.ts b/types/foundry/common/data/data/macro-data.d.ts deleted file mode 100644 index bb4480ca778..00000000000 --- a/types/foundry/common/data/data/macro-data.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -declare module foundry { - module data { - interface MacroSource extends abstract.DocumentSource { - _id: string; - name: string; - type: "chat" | "script"; - img: ImageFilePath; - actorIds: string[]; - author: string; - command: string; - scope: string; - folder?: string | null; - sort: number; - ownership: Record; - flags: Record>; - } - - class MacroData< - TDocument extends documents.BaseMacro = documents.BaseMacro - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface MacroData extends MacroSource { - readonly _source: MacroSource; - } - } -} diff --git a/types/foundry/common/data/data/measured-template-data.d.ts b/types/foundry/common/data/data/measured-template-data.d.ts deleted file mode 100644 index e0ad2a1456c..00000000000 --- a/types/foundry/common/data/data/measured-template-data.d.ts +++ /dev/null @@ -1,53 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a MeasuredTemplate embedded document. - * @see BaseMeasuredTemplate - * - * @param data Initial data used to construct the data object - * @param [document] The embedded document to which this data object belongs - * - * @property _id The _id which uniquely identifies this BaseMeasuredTemplate embedded document - * @property [t=circle] The value in CONST.MEASURED_TEMPLATE_TYPES which defines the geometry type of this template - * @property [x=0] The x-coordinate position of the origin of the template effect - * @property [y=0] The y-coordinate position of the origin of the template effect - * @property [distance] The distance of the template effect - * @property [direction=0] The angle of rotation for the measured template - * @property [angle=360] The angle of effect of the measured template, applies to cone types - * @property [width] The width of the measured template, applies to ray types - * @property [borderColor=#000000] A color string used to tint the border of the template shape - * @property [fillColor=#FF0000] A color string used to tint the fill of the template shape - * @property [texture] A repeatable tiling texture used to add a texture fill to the template shape - * @property [flags={}] An object of optional key/value flags - */ - interface MeasuredTemplateSource extends abstract.DocumentSource { - _id: string; - user: string; - t: MeasuredTemplateType; - x: number; - y: number; - distance: number; - direction: number; - angle: number; - width: number; - borderColor: HexColorString; - fillColor: HexColorString; - texture: ImageFilePath; - flags: Record; - } - - class MeasuredTemplateData< - TDocument extends documents.BaseMeasuredTemplate = documents.BaseMeasuredTemplate - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - protected override _initialize(): void; - - protected override _validateDocument(): void; - } - - interface MeasuredTemplateData extends MeasuredTemplateSource { - readonly _source: MeasuredTemplateSource; - } - } -} diff --git a/types/foundry/common/data/data/note-data.d.ts b/types/foundry/common/data/data/note-data.d.ts deleted file mode 100644 index b87814d62e8..00000000000 --- a/types/foundry/common/data/data/note-data.d.ts +++ /dev/null @@ -1,51 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a Note embedded document. - * @see BaseNote - * - * @param data Initial data used to construct the data object - * @param [document] The embedded document to which this data object belongs - * - * @property _id The _id which uniquely identifies this BaseNote embedded document - * @property [entryId=null] The _id of a JournalEntry document which this Note represents - * @property [x=0] The x-coordinate position of the center of the note icon - * @property [y=0] The y-coordinate position of the center of the note icon - * @property [icon] An image icon path used to represent this note - * @property [iconSize=40] The pixel size of the map note icon - * @property [iconTint] An optional color string used to tint the map note icon - * @property [text] Optional text which overrides the title of the linked Journal Entry - * @property [fontFamily=Signika] The font family used to display the text label on this note - * @property [fontSize=36] The font size used to display the text label on this note - * @property [textAnchor=1] A value in CONST.TEXT_ANCHOR_POINTS which defines where the text label anchors - * to the note icon. - * @property [textColor=#FFFFFF] The string that defines the color with which the note text is rendered - * @property [flags={}] An object of optional key/value flags - */ - interface NoteSource { - _id: string; - entryId: string | null; - x: number; - y: number; - icon: ImageFilePath; - iconSize: number; - iconTint: HexColorString; - text: string; - fontFamily: string; - fontSize: number; - textAnchor: number; - textColor: HexColorString; - flags: Record; - } - - class NoteData< - TDocument extends documents.BaseNote = documents.BaseNote - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface NoteData extends NoteSource { - readonly _source: NoteSource; - } - } -} diff --git a/types/foundry/common/data/data/playlist-data.d.ts b/types/foundry/common/data/data/playlist-data.d.ts deleted file mode 100644 index ba407a627cf..00000000000 --- a/types/foundry/common/data/data/playlist-data.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a Playlist document. - * @see BasePlaylist - * @property _id The _id which uniquely identifies this Playlist document - * @property name The name of this playlist - * @property sounds A Collection of PlaylistSounds embedded documents which belong to this playlist - * @property [mode=0] The playback mode for sounds in this playlist - * @property [playing=false] Is this playlist currently playing? - * @property folder The _id of a Folder which contains this playlist - * @property [sort] The numeric sort value which orders this playlist relative to its siblings - * @property [permission] An object which configures user permissions to this playlist - * @property [flags={}] An object of optional key/value flags - */ - interface PlaylistSource { - _id: string; - name: string; - sounds: PlaylistSoundSource[]; - mode: PlaylistMode; - playing: boolean; - fade: number; - folder: string; - sort: number; - seed: number; - permission: Record; - flags: Record; - } - - class PlaylistData< - TDocument extends documents.BasePlaylist = documents.BasePlaylist - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - sounds: abstract.EmbeddedCollection; - } - - interface PlaylistData extends Omit { - readonly _source: PlaylistSource; - } - } -} diff --git a/types/foundry/common/data/data/playlist-sound-data.d.ts b/types/foundry/common/data/data/playlist-sound-data.d.ts deleted file mode 100644 index 7b7cf19f9e3..00000000000 --- a/types/foundry/common/data/data/playlist-sound-data.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a PlaylistSound embedded document. - * @see BasePlaylistSound - * - * @param data Initial data used to construct the data object - * @param [document] The document to which this data object belongs - * - * @property _id The _id which uniquely identifies this PlaylistSound document - * @property name The name of this sound track - * @property path The audio file path that is played by this sound - * @property [playing=false] Is this sound currently playing? - * @property [repeat=false] Does this sound loop? - * @property [volume=0.5] The audio volume of the sound, from 0 to 1 - * @property [streaming=false] Does this audio file use the "large file streaming" mode? - * @property [flags={}] An object of optional key/value flags - */ - interface PlaylistSoundSource { - _id: string; - name: string; - path: string; - playing: boolean; - repeat: boolean; - volumn: number; - streaming: boolean; - flags: Record; - } - - class PlaylistSoundData< - TDocument extends documents.BasePlaylistSound = documents.BasePlaylistSound - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - protected override _initialize(): void; - } - - interface PlaylistSoundData extends PlaylistSoundSource { - readonly _source: PlaylistSoundSource; - } - } -} diff --git a/types/foundry/common/data/data/prototype-token-data.d.ts b/types/foundry/common/data/data/prototype-token-data.d.ts index 1a105f7ef5b..4daf91d8b29 100644 --- a/types/foundry/common/data/data/prototype-token-data.d.ts +++ b/types/foundry/common/data/data/prototype-token-data.d.ts @@ -2,27 +2,23 @@ declare namespace foundry { module data { interface PrototypeTokenSource extends Omit< - TokenSource, + documents.TokenSource, "_id" | "actorId" | "actorData" | "x" | "y" | "elevation" | "effects" | "overlayEffect" | "hidden" > { name: string; randomImg: boolean; } - class PrototypeToken< - TDocument extends documents.BaseActor = documents.BaseActor - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - + class PrototypeToken extends abstract.Document { protected override _initialize(): void; - override toJSON(): this["_source"]; + override toJSON(): RawObject; - lightAnimation: AnimationData; + lightAnimation: AnimationData; - bar1: TokenBarData; + bar1: documents.TokenBarData; - bar2: TokenBarData; + bar2: documents.TokenBarData; } interface PrototypeToken extends Omit { diff --git a/types/foundry/common/data/data/roll-table-data.d.ts b/types/foundry/common/data/data/roll-table-data.d.ts deleted file mode 100644 index d348c54df0a..00000000000 --- a/types/foundry/common/data/data/roll-table-data.d.ts +++ /dev/null @@ -1,57 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a RollTable document. - * @see BaseRollTable - * - * @param data Initial data used to construct the data object - * @param [document] The document to which this data object belongs - * - * @property _id The _id which uniquely identifies this RollTable document - * @property name The name of this RollTable - * @property [img] An image file path which provides the thumbnail artwork for this RollTable - * @property [description] The HTML text description for this RollTable document - * @property [results=[]] A Collection of TableResult embedded documents which belong to this RollTable - * @property formula The Roll formula which determines the results chosen from the table - * @property [replacement=true] Are results from this table drawn with replacement? - * @property [displayRoll=true] Is the Roll result used to draw from this RollTable displayed in chat? - * @property folder The _id of a Folder which contains this RollTable - * @property [sort] The numeric sort value which orders this RollTable relative to its siblings - * @property [permission] An object which configures user permissions to this RollTable - * @property [flags={}] An object of optional key/value flags - */ - interface RollTableSource { - _id: string; - name: string; - img?: ImageFilePath; - description: string; - results: TableResultSource[]; - formula: string; - replacement: boolean; - displayRoll: boolean; - folder?: string | null; - sort: number; - ownership: Record; - flags: Record>; - } - - class RollTableData< - TDocument extends documents.BaseRollTable = documents.BaseRollTable, - TResults extends documents.BaseTableResult = documents.BaseTableResult - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - /** The default icon used for newly created Macro documents */ - static DEFAULT_ICON: string; - - /** A Collection of TableResult embedded documents which belong to this RollTable */ - results: abstract.EmbeddedCollection; - } - - interface RollTableData extends Omit { - img: ImageFilePath; - - readonly _source: RollTableSource; - } - } -} diff --git a/types/foundry/common/data/data/scene-data.d.ts b/types/foundry/common/data/data/scene-data.d.ts deleted file mode 100644 index 0aa07069245..00000000000 --- a/types/foundry/common/data/data/scene-data.d.ts +++ /dev/null @@ -1,95 +0,0 @@ -declare module foundry { - module data { - interface SceneSource { - _id: string; - name: string; - - // Navigation - active: boolean; - navigation: boolean; - navOrder: number; - navName: string; - - // Canvas Dimensions - img: VideoFilePath; - foreground: VideoFilePath; - thumb: ImageFilePath; - width: number; - height: number; - padding: number; - initial: { - x: number; - y: number; - scale: number; - }; - - backgroundColor: HexColorString; - - grid: GridData; - - shiftX: number; - shiftY: number; - - // Vision and Lighting Configuration - tokenVision: boolean; - fogExploration: boolean; - fogReset: string; - globalLight: boolean; - globalLightThreshold: number; - hasGlobalThreshold: boolean; - darkness: number; - - // Embedded Collections - drawings: DrawingSource[]; - tokens: TokenSource[]; - lights: AmbientLightSource[]; - notes: NoteSource[]; - sounds: AmbientSoundSource[]; - templates: MeasuredTemplateSource[]; - tiles: TileSource[]; - walls: WallSource[]; - - // Linked Documents - playlist: PlaylistSource | null; - playlistSound: PlaylistSoundSource | null; - journal: documents.JournalEntrySource | null; - weather: string; - - // Permissions - folder: string | null; - sort: number; - ownership: Record; - flags: Record>; - } - - interface GridData { - /** The type of grid, a number from CONST.GRID_TYPES. */ - type: GridType; - /** The grid size which represents the width (or height) of a single grid space. */ - size: number; - /** A string representing the color used to render the grid lines. */ - color: HexColorString; - /** A number between 0 and 1 for the opacity of the grid lines. */ - alpha: number; - /** The number of distance units which are represented by a single grid space. */ - distance: number; - /** A label for the units of measure which are used for grid distance. */ - units: string; - } - - class SceneData< - TDocument extends documents.BaseScene = documents.BaseScene - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - // Linked Documents - playlist: documents.BasePlaylist | null; - playlistSound: documents.BasePlaylistSound | null; - journal: documents.BaseJournalEntry | null; - } - - interface SceneData extends Omit { - _source: SceneSource; - } - } -} diff --git a/types/foundry/common/data/data/table-result-data.d.ts b/types/foundry/common/data/data/table-result-data.d.ts deleted file mode 100644 index 12a1ec3e5a3..00000000000 --- a/types/foundry/common/data/data/table-result-data.d.ts +++ /dev/null @@ -1,41 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a TableResult embedded document within a Roll Table. - * @see BaseTableResult - * - * @param data Initial data used to construct the data object - * @param [document] The document to which this data object belongs - * - * @property [type=p] A result sub-type from CONST.TABLE_RESULT_TYPES - * @property [text] The text which describes the table result - * @property [img] An image file url that represents the table result - * @property [collection] A named collection from which this result is drawn - * @property [resultId] The _id of a Document within the collection this result references - * @property [weight=1] The probabilistic weight of this result relative to other results - * @property [range] A length 2 array of ascending integers which defines the range of dice roll - * totals which produce this drawn result - * @property [drawn=false] Has this result already been drawn (without replacement) - */ - interface TableResultSource { - type: TableResultType; - text: string; - img: ImageFilePath; - collection: string; - resultId: string; - weight: number; - range: [number, number]; - drawn: boolean; - } - - class TableResultData< - TDocument extends documents.BaseTableResult = documents.BaseTableResult - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface TableResultData extends TableResultSource { - readonly _source: TableResultSource; - } - } -} diff --git a/types/foundry/common/data/data/texture-data.d.ts b/types/foundry/common/data/data/texture-data.d.ts new file mode 100644 index 00000000000..a686381b2e3 --- /dev/null +++ b/types/foundry/common/data/data/texture-data.d.ts @@ -0,0 +1,20 @@ +declare module foundry { + module data { + interface TextureData { + /** The URL of the texture source. */ + src: string | null; + /** The scale of the texture in the X dimension. */ + scaleX: number; + /** The scale of the texture in the Y dimension. */ + scaleY: number; + /** The X offset of the texture with (0,0) in the top left. */ + offsetX: number; + /** The Y offset of the texture with (0,0) in the top left. */ + offsetY: number; + /** An angle of rotation by which this texture is rotated around its center. */ + rotation: number; + /** An optional color string used to tint the texture. */ + tint: number | null; + } + } +} diff --git a/types/foundry/common/data/data/tile-data.d.ts b/types/foundry/common/data/data/tile-data.d.ts deleted file mode 100644 index edf970db8bd..00000000000 --- a/types/foundry/common/data/data/tile-data.d.ts +++ /dev/null @@ -1,57 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a Tile embedded document. - * @see BaseTile - * - * @property _id The _id which uniquely identifies this Tile embedded document - * @property [img] An image or video file path which this tile displays - * @property [width=0] The pixel width of the tile - * @property [height=0] The pixel height of the tile - * @property [x=0] The x-coordinate position of the top-left corner of the tile - * @property [y=0] The y-coordinate position of the top-left corner of the tile - * @property [z=100] The z-index ordering of this tile relative to its siblings - * @property [rotation=0] The angle of rotation for the tile between 0 and 360 - * @property [alpha=1] The tile opacity - * @property [tint] A color to tint the tile - * @property [hidden=false] Is the tile currently hidden? - * @property [locked=false] Is the tile currently locked? - * @property [overhead=false] Is the tile an overhead tile? - * @property [occlusion] The tile's occlusion settings - * @property [video] The tile's video settings - * @property [flags={}] An object of optional key/value flags - */ - interface TileSource { - _id: string; - img: ImageFilePath | null; - width: number; - height: number; - x: number; - y: number; - z: number; - rotation: number; - alpha: number; - tint: HexColorString | null; - hidden: boolean; - locked: boolean; - overhead: boolean; - video: VideoSource; - occlusion: TileOcclusionSource; - flags: Record; - } - - class TileData< - TDocument extends documents.BaseTile = documents.BaseTile - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface TileData extends TileSource { - readonly _source: TileSource; - - occlusion: TileOcclusion; - - video: VideoData; - } - } -} diff --git a/types/foundry/common/data/data/tile-occlusion.d.ts b/types/foundry/common/data/data/tile-occlusion.d.ts index a1665215724..9e049903560 100644 --- a/types/foundry/common/data/data/tile-occlusion.d.ts +++ b/types/foundry/common/data/data/tile-occlusion.d.ts @@ -6,21 +6,10 @@ declare module foundry { * @property alpha The occlusion alpha between 0 and 1 * @property [radius] An optional radius of occlusion used for RADIAL mode */ - interface TileOcclusionSource { + interface TileOcclusion { mode: TileOcclusionMode; alpha: number; radius?: number; } - - /** An inner-object which defines the schema for how Tile occlusion settings are defined */ - class TileOcclusion< - TDocument extends documents.BaseTile = documents.BaseTile - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface TileOcclusion extends TileOcclusionSource { - readonly _source: TileOcclusionSource; - } } } diff --git a/types/foundry/common/data/data/token-bar-data.d.ts b/types/foundry/common/data/data/token-bar-data.d.ts deleted file mode 100644 index 5955fe1fc78..00000000000 --- a/types/foundry/common/data/data/token-bar-data.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -declare namespace foundry { - module data { - /** - * An embedded data structure for the contents of a Token attribute bar. - * @property [attribute] The attribute path within the Token's Actor data which should be displayed - */ - interface TokenBarSource { - attribute: string | null; - } - - class TokenBarData< - TDocument extends documents.BaseToken | documents.BaseActor = documents.BaseToken | documents.BaseActor - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - } - - interface TokenBarData extends TokenBarSource { - readonly _source: TokenBarSource; - } - } -} diff --git a/types/foundry/common/data/data/token-data.d.ts b/types/foundry/common/data/data/token-data.d.ts deleted file mode 100644 index 24290a2c574..00000000000 --- a/types/foundry/common/data/data/token-data.d.ts +++ /dev/null @@ -1,128 +0,0 @@ -declare module foundry { - module data { - /** - * The data schema for a Token document. - * @extends foundry.abstract.DocumentData - * @memberof data - * - * @param data Initial data used to construct the data object - * @param [document] The document to which this data object belongs - * - * @property _id The Token _id which uniquely identifies it within its parent Scene - * @property name The name used to describe the Token - * @property [displayName=0] The display mode of the Token nameplate, from CONST.TOKEN_DISPLAY_MODES - * @property actorId The _id of an Actor document which this Token represents - * @property [actorLink=false] Does this Token uniquely represent a singular Actor, or is it one of many? - * @property [actorData] Token-level data which overrides the base data of the associated Actor - * @property [width=1] The width of the Token in grid units - * @property [height=1] The height of the Token in grid units - * @property [scale=1] A scale factor applied to the Token image, between 0.25 and 3 - * @property [mirrorX=false] Flip the Token image horizontally? - * @property [mirrorY=false] Flip the Token image vertically? - * @property [x=0] The x-coordinate of the top-left corner of the Token - * @property [y=0] The y-coordinate of the top-left corner of the Token - * @property [elevation=0] The vertical elevation of the Token, in distance units - * @property [lockRotation=false] Prevent the Token image from visually rotating? - * @property [rotation=0] The rotation of the Token in degrees, from 0 to 360. A value of 0 represents a southward-facing Token. - * @property [effects] An array of effect icon paths which are displayed on the Token - * @property [overlayEffect] A single icon path which is displayed as an overlay on the Token - * @property [hidden=false] Is the Token currently hidden from player view? - * @property [vision] Is this Token a source of vision? - * @property [dimSight=0] How far in distance units the Token can naturally see as if in dim light - * @property [brightSight=0] How far in distance units the Token can naturally see as if in bright light - * @property [sightAngle=360] The angle at which this Token is able to see, if it has vision - * @property [light] The angle at which this Token is able to see, if it has vision - * @property [dimLight=0] How far in distance units this Token emits dim light - * @property [brightLight=0] How far in distance units this Token emits bright light - * @property [lightAngle=360] The angle at which this Token is able to emit light - * @property [lightAnimation] A data object which configures token light animation settings - * @property [disposition=-1] A displayed Token disposition from CONST.TOKEN_DISPOSITIONS - * @property [displayBars=0] The display mode of Token resource bars, from CONST.TOKEN_DISPLAY_MODES - * @property [bar1] The configuration of the Token's primary resource bar - * @property [bar2] The configuration of the Token's secondary resource bar - * @property [flags={}] An object of optional key/value flags - */ - interface TokenSource extends TokenLightData { - _id: string; - name: string; - - // Navigation - active: boolean; - navigation: boolean; - navOrder: number; - navName: string; - - actorId: string | null; - actorLink: boolean; - actorData: DeepPartial; - mirrorX: boolean; - mirrorY: boolean; - height: number; - width: number; - x: number; - y: number; - elevation: number; - lockRotation: boolean; - effects: VideoFilePath[]; - overlayEffect: string | null; - vision: boolean; - dimSight: number; - brightSight: number; - sightAngle: number; - light: LightSource; - hidden: boolean; - texture: { - src: VideoFilePath; - scaleX: number; - scaleY: number; - offsetX: number; - offsetY: number; - rotation: number | null; - tint: `#${string}`; - }; - - lightAnimation: AnimationSource; - disposition: TokenDisposition; - displayName: TokenDisplayMode; - displayBars: TokenDisplayMode; - bar1: TokenBarSource; - bar2: TokenBarSource; - flags: Record>; - } - - class TokenData< - TDocument extends documents.BaseToken = documents.BaseToken - > extends abstract.DocumentData { - lightAnimation: AnimationData; - - bar1: TokenBarData; - - bar2: TokenBarData; - } - - interface TokenData extends Omit { - readonly _source: TokenSource; - - light: LightData>; - } - - namespace TokenData { - const schema: ReturnType<(typeof TokenData)["defineSchema"]>; - - const _schema: ReturnType<(typeof TokenData)["defineSchema"]> | undefined; - } - } -} - -declare interface TokenLightData { - brightLight: number; - dimLight: number; - lightAlpha: number; - lightAngle: number; - lightAnimation: { - type: string; - speed: number; - intensity: number; - }; - lightColor: string; -} diff --git a/types/foundry/common/data/data/video-data.d.ts b/types/foundry/common/data/data/video-data.d.ts index 1ae7b5b9b80..ff355433404 100644 --- a/types/foundry/common/data/data/video-data.d.ts +++ b/types/foundry/common/data/data/video-data.d.ts @@ -6,22 +6,10 @@ declare module foundry { * @property autoplay Should the video play automatically? * @property volume The volume level of any audio that the video file contains */ - interface VideoSource { + interface VideoData { loop: boolean; autoplay: boolean; volume: boolean; } - - class VideoData< - TDocument extends abstract.Document = abstract.Document - > extends abstract.DocumentData { - static override defineSchema(): abstract.DocumentSchema; - - protected override _initialize(): void; - } - - interface VideoData extends VideoSource { - readonly _source: VideoSource; - } } } diff --git a/types/foundry/common/data/data/wall-data.d.ts b/types/foundry/common/data/data/wall-data.d.ts deleted file mode 100644 index d814d51dde0..00000000000 --- a/types/foundry/common/data/data/wall-data.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -declare module foundry { - module data { - interface WallSource extends abstract.DocumentSource { - c: number[]; - move?: number; - sense?: number; - dir?: number; - door?: number; - ds?: number; - } - - /** - * The data schema for a Wall document. - * @see BaseWall - * - * @param data Initial data used to construct the data object - * @param [document] The embedded document to which this data object belongs - * - * @property _id The _id which uniquely identifies the embedded Wall document - * @property c The wall coordinates, a length-4 array of finite numbers [x0,y0,x1,y1] - * @property [move=0] The movement restriction type of this wall - * @property [sense=0] The sensory restriction type of this wall - * @property [dir=0] The direction of effect imposed by this wall - * @property [door=0] The type of door which this wall contains, if any - * @property [ds=0] The state of the door this wall contains, if any - */ - class WallData< - TDocument extends documents.BaseWall = documents.BaseWall - > extends abstract.DocumentData { - /** The data schema for a WallData object */ - static override defineSchema(): abstract.DocumentSchema; - } - - interface WallData extends WallSource { - readonly _source: WallSource; - } - } -} diff --git a/types/foundry/common/documents/active-effect.d.ts b/types/foundry/common/documents/active-effect.d.ts index 49b61c6169b..b58001bead3 100644 --- a/types/foundry/common/documents/active-effect.d.ts +++ b/types/foundry/common/documents/active-effect.d.ts @@ -5,14 +5,14 @@ declare module foundry { * @param data Initial data from which to construct the document. * @property data The constructed data object for the document. */ - class BaseActiveEffect extends abstract.Document { - static override get schema(): typeof data.ActiveEffectData; - + class BaseActiveEffect< + TParent extends BaseActor | BaseItem | null + > extends abstract.Document { static override get metadata(): ActiveEffectMetadata; protected override _preCreate( - data: PreDocumentId, - options: DocumentModificationContext, + data: PreDocumentId, + options: DocumentModificationContext, user: BaseUser ): Promise; @@ -23,10 +23,66 @@ declare module foundry { ): boolean; } - interface BaseActiveEffect { - readonly data: data.ActiveEffectData; + interface BaseActiveEffect | null> + extends abstract.Document { + readonly _source: ActiveEffectSource; + } + + /** + * @property _id The EmbeddedEntity id of the Active Effect + * @property label The label which describes this effect + * @property [disabled] Is this effect currently disabled? + * @property [icon] An image icon path for this effect + * @property [tint] A hex color string to tint the effect icon + * @property [origin] The UUID of an Entity or EmbeddedEntity which was the source of this effect + * @property [transfer] Should this effect transfer automatically to an Actor when its Item becomes owned? + * @property flags Additional key/value flags + */ + interface ActiveEffectSource { + _id: string; + label: string; + duration: EffectDurationSource; + changes: EffectChangeSource[]; + disabled: boolean; + icon: ImageFilePath; + tint: string; + origin: string | undefined; + transfer: boolean; + flags: Record; + } + + /** + * An embedded data structure which tracks the duration of an ActiveEffect. + * @property startTime The world time when the active effect first started + * @property [seconds] The maximum duration of the effect, in seconds + * @property [combat] The _id of the CombatEncounter in which the effect first started + * @property [rounds] The maximum duration of the effect, in combat rounds + * @property [turns] The maximum duration of the effect, in combat turns + * @property [startRound] The round of the CombatEncounter in which the effect first started + * @property [startTurn] The turn of the CombatEncounter in which the effect first started + */ + interface EffectDurationSource { + startTime: number; + seconds: number | undefined; + combat?: string; + rounds: number | undefined; + turns: number | undefined; + startRound: number | null; + startTurn: number | null; + } - readonly parent: BaseActor | BaseItem; + /** + * An embedded data structure which defines the structure of a change applied by an ActiveEffect. + * @property key The attribute path in the Actor or Item data which the change modifies + * @property value The value of the change effect + * @property mode The modification mode with which the change is applied + * @property priority The priority level with which this change is applied + */ + interface EffectChangeSource { + key: string; + value: string; + mode: ActiveEffectChangeMode; + priority: number; } interface ActiveEffectMetadata extends abstract.DocumentMetadata { diff --git a/types/foundry/common/documents/actor.d.ts b/types/foundry/common/documents/actor.d.ts index 466c8ce5aea..9798fa7ab47 100644 --- a/types/foundry/common/documents/actor.d.ts +++ b/types/foundry/common/documents/actor.d.ts @@ -5,8 +5,8 @@ declare module foundry { * @param data Initial data from which to construct the document. * @property data The constructed data object for the document. */ - class BaseActor extends abstract.Document { - prototypeToken: foundry.data.PrototypeToken; + class BaseActor extends abstract.Document { + prototypeToken: data.PrototypeToken; /** The default icon used for newly created Actor documents */ static DEFAULT_ICON: ImageFilePath; @@ -14,10 +14,10 @@ declare module foundry { static override get metadata(): ActorMetadata; /** A Collection of Item embedded Documents */ - readonly items: abstract.EmbeddedCollection; + readonly items: abstract.EmbeddedCollection>; /** A Collection of ActiveEffect embedded Documents */ - readonly effects: abstract.EmbeddedCollection; + readonly effects: abstract.EmbeddedCollection>; /** * Migrate the system data object to conform to data model defined by the current system version. @@ -40,31 +40,69 @@ declare module foundry { protected override _preCreate( data: PreDocumentId, - options: DocumentModificationContext, + options: DocumentModificationContext, user: BaseUser ): Promise; protected override _preUpdate( - changed: DocumentUpdateData, - options: DocumentModificationContext, + changed: DocumentUpdateData, + options: DocumentModificationContext, user: BaseUser ): Promise; } - interface BaseActor { + interface BaseActor extends abstract.Document { flags: ActorFlags; - readonly _source: data.ActorSource; - readonly parent: BaseToken | null; + readonly _source: ActorSource; system: object; get documentName(): (typeof BaseActor)["metadata"]["name"]; } - type ActorFlags = DocumentFlags & { + /** + * The data schema for a Actor document. + * @see BaseActor + * + * @param data Initial data used to construct the data object + * @param [document] The document to which this data object belongs + * + * @property _id The _id which uniquely identifies this Actor document + * @property name The name of this Actor + * @property type An Actor subtype which configures the system data model applied + * @property [img] An image file path which provides the artwork for this Actor + * @property [data] The system data object which is defined by the system template.json model + * @property [token] Default Token settings which are used for Tokens created from this Actor + * @property items A Collection of Item embedded Documents + * @property effects A Collection of ActiveEffect embedded Documents + * @property folder The _id of a Folder which contains this Actor + * @property [sort] The numeric sort value which orders this Actor relative to its siblings + * @property [ownership] An object which configures user permissions to this Actor + * @property [flags={}] An object of optional key/value flags + */ + interface ActorSource< + TType extends string = string, + TSystemSource extends object = object, + TItemSource extends ItemSource = ItemSource + > { + _id: string; + name: string; + type: TType; + img: ImageFilePath; + system: TSystemSource; + prototypeToken: data.PrototypeTokenSource; + items: TItemSource[]; + effects: ActiveEffectSource[]; + folder: string | null; + sort: number; + ownership: Record; + flags: ActorFlags; + } + + interface ActorFlags extends DocumentFlags { core?: { sourceId?: ActorUUID; }; - }; + } interface ActorMetadata extends abstract.DocumentMetadata { name: "Actor"; diff --git a/types/foundry/common/documents/adventure.d.ts b/types/foundry/common/documents/adventure.d.ts new file mode 100644 index 00000000000..2ea3282af6f --- /dev/null +++ b/types/foundry/common/documents/adventure.d.ts @@ -0,0 +1,75 @@ +declare module foundry { + module documents { + /** + * The base User document, which is extended by both the server and client. + * This base User provides shared functionality which is consistent for both sides of the application. + * Each client who connects to a Foundry Virtual Tabletop session assumes the identity of one (and only one) User. + * + * @param data Initial data from which to construct the document. + * @property data The constructed data object for the document. + */ + class BaseAdventure extends abstract.Document { + static override get metadata(): AdventureMetadata; + + /* ---------------------------------------- */ + /* Permissions */ + /* ---------------------------------------- */ + + /** Test whether the User has a GAMEMASTER or ASSISTANT role in this World? */ + get isGM(): boolean; + + /** + * Test whether the User is able to perform a certain permission action. + * The provided permission string may pertain to an explicit permission setting or a named user role. + * Alternatively, Gamemaster users are assumed to be allowed to take all actions. + * + * @param action The action to test + * @return Does the user have the ability to perform this action? + */ + can(action: UserAction): boolean; + + getUserLevel(user: BaseUser): DocumentOwnershipLevel; + + /** + * Test whether the User has at least a specific permission + * @param permission The permission name from USER_PERMISSIONS to test + * @return Does the user have at least this permission + */ + hasPermission(permission: UserPermission): boolean; + + /** + * Test whether the User has at least the permission level of a certain role + * @param role The role name from USER_ROLES to test + * @param [exact] Require the role match to be exact + * @return Does the user have at this role level (or greater)? + */ + hasRole(role: UserRole | UserRoleName, { exact }?: { exact: boolean }): boolean; + } + + interface BaseAdventure extends abstract.Document { + readonly _source: AdventureSource; + + get documentName(): "Adventure"; + } + + interface AdventureMetadata extends abstract.DocumentMetadata { + name: "Adventure"; + collection: "Adventures"; + label: "DOCUMENT.Adventure"; + isPrimary: true; + } + + interface AdventureSource { + _id: string; + avatar: ImageFilePath; + img: ImageFilePath; + character: string | null; + color: HexColorString; + hotbar: Record; + name: string; + password: string; + role: UserRole; + flags: DocumentFlags; + } + } +} diff --git a/types/foundry/common/documents/ambient-light.d.ts b/types/foundry/common/documents/ambient-light.d.ts index 14b05931571..aa04778f7a7 100644 --- a/types/foundry/common/documents/ambient-light.d.ts +++ b/types/foundry/common/documents/ambient-light.d.ts @@ -1,20 +1,42 @@ declare module foundry { module documents { /** The AmbientLight embedded document model. */ - class BaseAmbientLight extends abstract.Document { - static override get schema(): typeof data.AmbientLightData; - + class BaseAmbientLight extends abstract.Document { static override get metadata(): AmbientLightMetadata; + config: data.LightSource; + protected override _initialize(): void; } - interface BaseAmbientLight { - config: foundry.data.LightData; - - readonly data: data.AmbientLightData; + interface BaseAmbientLight extends abstract.Document { + readonly _source: AmbientLightSource; + } - readonly parent: BaseScene | null; + /** + * The data schema for a AmbientLight embedded document. + * + * @property _id The _id which uniquely identifies this BaseAmbientLight embedded document + * @property [x=0] The x-coordinate position of the origin of the light + * @property [y=0] The y-coordinate position of the origin of the light + * @property [rotation=0] The angle of rotation for the tile between 0 and 360 + * @property [walls=true] Whether or not this light source is constrained by Walls + * @property [vision=false] Whether or not this light source provides a source of vision + * @property config Light configuration data + * @property [hidden=false] Is the light source currently hidden? + * @property [flags={}] An object of optional key/value flags + */ + interface AmbientLightSource { + _id: string; + t: string; + x: number; + y: number; + rotation: number; + walls: boolean; + vision: boolean; + config: data.LightSource; + hidden: boolean; + flags: Record; } interface AmbientLightMetadata extends abstract.DocumentMetadata { diff --git a/types/foundry/common/documents/ambient-sound.d.ts b/types/foundry/common/documents/ambient-sound.d.ts index 5ebd9ffd97a..7e5085a8ec4 100644 --- a/types/foundry/common/documents/ambient-sound.d.ts +++ b/types/foundry/common/documents/ambient-sound.d.ts @@ -1,16 +1,12 @@ declare module foundry { module documents { /** The AmbientSound embedded document model. */ - class BaseAmbientSound extends abstract.Document { - static override get schema(): typeof data.AmbientSoundData; - + class BaseAmbientSound extends abstract.Document { static override get metadata(): AmbientSoundMetadata; } - interface BaseAmbientSound { - readonly data: data.AmbientSoundData; - - readonly parent: BaseScene | null; + interface BaseAmbientSound extends abstract.Document { + readonly _source: AmbientSoundSource; } interface AmbientSoundMetadata extends abstract.DocumentMetadata { @@ -20,5 +16,34 @@ declare module foundry { isEmbedded: true; types: ["l", "g"]; } + + /** + * The data schema for a AmbientSound embedded document. + * @see BaseAmbientSound + * + * @param data Initial data used to construct the data object + * @param [document] The document to which this data object belongs + * + * @property _id The _id which uniquely identifies this AmbientSound document + * @property path The audio file path that is played by this sound + * @property [playing=false] Is this sound currently playing? + * @property [repeat=false] Does this sound loop? + * @property [volume=0.5] The audio volume of the sound, from 0 to 1 + * @property [flags={}] An object of optional key/value flags + */ + interface AmbientSoundSource { + _id: string; + type: string; + x: number; + y: number; + radius: number; + path: AudioFilePath; + repeat: boolean; + volume: number; + easing: boolean; + hidden: boolean; + darkness: data.DarknessActivation; + flags: DocumentFlags; + } } } diff --git a/types/foundry/common/documents/cards.d.ts b/types/foundry/common/documents/cards.d.ts index 45d3b9606a8..76a52a08b73 100644 --- a/types/foundry/common/documents/cards.d.ts +++ b/types/foundry/common/documents/cards.d.ts @@ -1,13 +1,11 @@ declare module foundry { module documents { /** The base Cards definition which defines common behavior of an Cards document shared by both client and server. */ - class BaseCards extends abstract.Document { - static override get schema(): ConstructorOf; - + class BaseCards extends abstract.Document { static override get metadata(): abstract.DocumentMetadata; /** The sub-type of Card. */ - get type(): string; + readonly type: string; /** Is a User able to create a new embedded Card document within this parent? */ protected static _canCreate(user: BaseUser, doc: BaseCards, data: object): boolean; @@ -22,10 +20,47 @@ declare module foundry { ): boolean; } - interface BaseCards extends abstract.Document { - readonly data: data.CardsData; + interface BaseCards extends abstract.Document { + readonly _source: CardsSource; get documentName(): "Cards"; } + + /** + * The data schema of a stack of multiple Cards. + * Each stack can represent a Deck, a Hand, or a Pile. + */ + interface CardsSource<> { + /** The _id which uniquely identifies this stack of Cards document */ + _id: string; + /** The text name of this stack */ + name: string; + /** The type of this stack, in BaseCards.metadata.types */ + type: string; + /** A text description of this stack */ + description: string; + /** An image or video which is used to represent the stack of cards */ + img: VideoFilePath; + /** Game system data which is defined by the system template.json model */ + data: object; + /** A collection of Card documents which currently belong to this stack */ + cards: object; + /** The visible width of this stack */ + width: number; + /** The visible height of this stack */ + height: number; + /** The angle of rotation of this stack */ + rotation: string; + /** Whether or not to publicly display the number of cards in this stack */ + displayCount?: boolean; + /** The _id of a Folder which contains this document */ + folder?: string | null; + /** The sort order of this stack relative to others in its parent collection */ + sort: number; + /** An object which configures user permissions to this stack */ + ownership: Record; + /** An object of optional key/value flags */ + flags: Record>; + } } } diff --git a/types/foundry/common/documents/chat-message.d.ts b/types/foundry/common/documents/chat-message.d.ts index 12163b42149..4e36e63683d 100644 --- a/types/foundry/common/documents/chat-message.d.ts +++ b/types/foundry/common/documents/chat-message.d.ts @@ -8,47 +8,82 @@ declare module foundry { * @param data Initial data from which to construct the document. * @property data The constructed data object for the document. */ - class BaseChatMessage extends abstract.Document { + class BaseChatMessage extends abstract.Document { blind: boolean; content: string; - flags: foundry.data.ChatMessageFlags; + flags: ChatMessageFlags; rolls: Rolled[]; - speaker: foundry.data.ChatSpeakerSource; + speaker: ChatSpeakerData; type: ChatMessageType; whisper: string[]; - static override get schema(): typeof data.ChatMessageData; - static override get metadata(): ChatMessageMetadata; /** Is a user able to create a new chat message? */ - protected static _canCreate(user: documents.BaseUser, doc: documents.BaseChatMessage): boolean; + protected static _canCreate(user: BaseUser, doc: BaseChatMessage): boolean; /** Is a user able to update an existing chat message? */ - protected static _canUpdate( - user: documents.BaseUser, - doc: documents.BaseChatMessage, - data: data.ChatMessageData - ): boolean; + protected static _canUpdate(user: BaseUser, doc: BaseChatMessage, data: ChatMessageSource): boolean; /** Is a user able to delete an existing chat message? */ - protected static _canDelete(user: documents.BaseUser, doc: documents.BaseChatMessage): boolean; + protected static _canDelete(user: BaseUser, doc: BaseChatMessage): boolean; - static createDocuments( - this: ConstructorOf, - data?: (T | PreCreate)[], + static override createDocuments>( + this: ConstructorOf, + data?: (TDocument | PreCreate)[], context?: ChatMessageModificationContext - ): Promise; + ): Promise; } - interface BaseChatMessage { - readonly parent: null; + interface BaseChatMessage extends abstract.Document { + readonly _source: ChatMessageSource; get documentName(): "ChatMessage"; } - interface ChatMessageModificationContext extends DocumentModificationContext { - rollMode: RollMode; + interface ChatMessageSource { + _id: string; + type: ChatMessageType; + user: string; + timestamp: string; + flavor?: string; + content: string; + speaker: ChatSpeakerData; + whisper: string[]; + blind: boolean; + rolls: (string | RollJSON)[]; + sound: AudioFilePath; + emote?: boolean; + flags: ChatMessageFlags; + } + + interface ChatMessageFlags extends DocumentFlags { + core?: { + canPopout?: boolean; + initiativeRoll?: boolean; + RollTable?: string; + }; + } + + /** + * The data schema for an embedded Chat Speaker object. + * @extends DocumentData + * @memberof data + * @see ChatMessageData + * + * @param data Initial data used to construct the data object + * @param [document] The document to which this data object belongs + * + * @property [scene] The _id of the Scene where this message was created + * @property [actor] The _id of the Actor who generated this message + * @property [token] The _id of the Token who generated this message + * @property [alias] An overridden alias name used instead of the Actor or Token name + */ + interface ChatSpeakerData { + scene?: string | null; + actor?: string | null; + token?: string | null; + alias: string; } interface ChatMessageMetadata extends abstract.DocumentMetadata { @@ -64,3 +99,7 @@ declare module foundry { } } } + +declare interface ChatMessageModificationContext extends DocumentModificationContext { + rollMode?: RollMode | "roll"; +} diff --git a/types/foundry/common/documents/combat.d.ts b/types/foundry/common/documents/combat.d.ts index 97bf7579790..3cc4c1ba3a4 100644 --- a/types/foundry/common/documents/combat.d.ts +++ b/types/foundry/common/documents/combat.d.ts @@ -1,22 +1,20 @@ declare module foundry { module documents { /** The Combat document model. */ - class BaseCombat extends abstract.Document { - static override get schema(): typeof data.CombatData; - + class BaseCombat extends abstract.Document { static override get metadata(): CombatMetadata; + flags: DocumentFlags; + /** A reference to the Collection of Combatant instances in the Combat document, indexed by id. */ - readonly combatants: this["data"]["combatants"]; + readonly combatants: abstract.EmbeddedCollection>; /** Is a user able to update an existing Combat? */ - protected static _canUpdate(user: documents.BaseUser, doc: BaseCombat, data: data.CombatData): boolean; + protected static _canUpdate(user: documents.BaseUser, doc: BaseCombat, data: CombatSource): boolean; } - interface BaseCombat { - readonly data: data.CombatData; - - readonly parent: null; + interface BaseCombat extends abstract.Document { + readonly _source: CombatSource; get documentName(): "Combat"; } @@ -35,5 +33,27 @@ declare module foundry { delete: "ASSISTANT"; }; } + + /** + * The data schema for a Combat document. + * @property _id The _id which uniquely identifies this Combat document + * @property scene The _id of a Scene within which this Combat occurs + * @property combatants A Collection of Combatant embedded Documents + * @property [active=false] Is the Combat encounter currently active? + * @property [round=0] The current round of the Combat encounter + * @property [turn=0] The current turn in the Combat round + * @property [sort=0] The current sort order of this Combat relative to others in the same Scene + * @property [flags={}] An object of optional key/value flags + */ + interface CombatSource { + _id: string; + scene: string; + combatants: CombatantSource[]; + active: boolean; + round: number; + turn: number; + sort: number; + flags: DocumentFlags; + } } } diff --git a/types/foundry/common/documents/combatant.d.ts b/types/foundry/common/documents/combatant.d.ts index 8e1e773237f..7159970ab01 100644 --- a/types/foundry/common/documents/combatant.d.ts +++ b/types/foundry/common/documents/combatant.d.ts @@ -1,23 +1,21 @@ declare module foundry { module documents { /** The Combat document model. */ - class BaseCombatant extends abstract.Document { - static override get schema(): typeof data.CombatantData; - + class BaseCombatant extends abstract.Document { static override get metadata(): CombatantMetadata; + flags: DocumentFlags; + /** Is a user able to update an existing Combatant? */ protected static _canUpdate( user: documents.BaseUser, - doc: BaseCombatant, - data: data.CombatantData + doc: BaseCombatant, + data: CombatantSource ): boolean; } - interface BaseCombatant extends data.CombatantSource { - readonly data: foundry.data.CombatantData; - - readonly parent: BaseCombat | null; + interface BaseCombatant extends CombatantSource, abstract.Document { + readonly _source: CombatantSource; } interface CombatantMetadata extends abstract.DocumentMetadata { @@ -31,5 +29,27 @@ declare module foundry { delete: "ASSISTANT"; }; } + + /** + * The data schema for a Combat document. + * @property _id The _id which uniquely identifies this Combatant embedded document + * @property [tokenId] The _id of a Token associated with this Combatant + * @property [name] A customized name which replaces the name of the Token in the tracker + * @property [img] A customized image which replaces the Token image in the tracker + * @property [initiative] The initiative score for the Combatant which determines its turn order + * @property [hidden=false] Is this Combatant currently hidden? + * @property [defeated=false] Has this Combatant been defeated? + * @property [flags={}] An object of optional key/value flags + */ + interface CombatantSource { + _id: string | null; + actorId: string; + tokenId: string; + img: VideoFilePath; + initiative: number | null; + hidden: boolean; + defeated: boolean; + flags: DocumentFlags; + } } } diff --git a/types/foundry/common/documents/drawing.d.ts b/types/foundry/common/documents/drawing.d.ts index 6573aec9828..5e7386b0afd 100644 --- a/types/foundry/common/documents/drawing.d.ts +++ b/types/foundry/common/documents/drawing.d.ts @@ -1,19 +1,76 @@ declare module foundry { module documents { /** The Drawing embedded document model. */ - class BaseDrawing extends abstract.Document { - static override get schema(): typeof data.DrawingData; - + class BaseDrawing extends abstract.Document { static override get metadata(): DrawingMetadata; /** Is a user able to update or delete an existing Drawing document? */ - protected static _canModify(user: BaseUser, doc: BaseDrawing, data: data.DrawingData): boolean; + protected static _canModify( + user: BaseUser, + doc: BaseDrawing, + data: DrawingSource + ): boolean; } - interface BaseDrawing { - readonly data: data.DrawingData; + interface BaseDrawing extends abstract.Document { + readonly _source: DrawingSource; + } - readonly parent: BaseScene | null; + /** + * The data schema for a Drawing embedded document. + * @see BaseDrawing + * + * @param data Initial data used to construct the data object + * @param [document] The embedded document to which this data object belongs + * + * @property t The value in CONST.DRAWING_TYPES which defines the geometry type of this drawing + * @property x The x-coordinate position of the top-left corner of the drawn shape + * @property y The y-coordinate position of the top-left corner of the drawn shape + * @property width The pixel width of the drawing figure + * @property height The pixel height of the drawing figure + * @property [rotation=0] The angle of rotation for the drawing figure + * @property [z=0] The z-index of this drawing relative to other siblings + * @property [points] An array of points [x,y] which define polygon vertices + * @property [bezierFactor=0] An amount of bezier smoothing applied, between 0 and 1 + * @property [fillType=0] The fill type of the drawing shape, a value from CONST.DRAWING_FILL_TYPES + * @property [fillColor] An optional color string with which to fill the drawing geometry + * @property [fillAlpha=0.5] The opacity of the fill applied to the drawing geometry + * @property [strokeWidth=8] The width in pixels of the boundary lines of the drawing geometry + * @property [strokeColor] The color of the boundary lines of the drawing geometry + * @property [strokeAlpha=1] The opacity of the boundary lines of the drawing geometry + * @property [texture] The path to a tiling image texture used to fill the drawing geometry + * @property [text] Optional text which is displayed overtop of the drawing + * @property [fontFamily=Signika] The font family used to display text within this drawing + * @property [fontSize=48] The font size used to display text within this drawing + * @property [textColor=#FFFFFF] The color of text displayed within this drawing + * @property [textAlpha=1] The opacity of text displayed within this drawing + * @property [hidden=false] Is the drawing currently hidden? + * @property [locked=false] Is the drawing currently locked? + */ + interface DrawingSource { + t: DrawingShapeType; + x: number; + y: number; + width: number; + height: number; + rotation?: number; + z?: number; + points?: [number, number][]; + bezierFactor?: number; + fillType?: number; + fillColor?: string; + fillAlpha?: number; + strokeWidth?: number; + strokeColor?: number; + strokeAlpha?: number; + texture?: string; + text?: string; + fontFamily?: string; + fontSize?: number; + textColor?: string; + textAlpha?: number; + hidden?: boolean; + locked?: boolean; } interface DrawingMetadata extends abstract.DocumentMetadata { diff --git a/types/foundry/common/documents/fog-exploration.d.ts b/types/foundry/common/documents/fog-exploration.d.ts index caf1ee6be1c..38f6419dbc5 100644 --- a/types/foundry/common/documents/fog-exploration.d.ts +++ b/types/foundry/common/documents/fog-exploration.d.ts @@ -1,14 +1,12 @@ declare module foundry { module documents { /** The FogExploration Document model. */ - class BaseFogExploration extends foundry.abstract.Document { - static override get schema(): typeof data.FogExplorationData; - + class BaseFogExploration extends abstract.Document { static override get metadata(): FogExplorationMetadata; protected override _preUpdate( changed: DocumentUpdateData, - options: DocumentModificationContext, + options: DocumentModificationContext, user: BaseUser ): Promise; @@ -16,10 +14,8 @@ declare module foundry { protected static _canUserModify(user: BaseUser, doc: T): boolean; } - interface BaseFogExploration { - readonly data: data.FogExplorationData; - - readonly parent: null; + interface BaseFogExploration extends abstract.Document { + readonly _source: FogExplorationSource; } interface FogExplorationMetadata extends abstract.DocumentMetadata { @@ -33,5 +29,23 @@ declare module foundry { delete: (typeof BaseFogExploration)["_canUserModify"]; }; } + + /** + * The data schema for a FogExploration document. + * @property _id The _id which uniquely identifies this FogExploration document + * @property scene The _id of the Scene document to which this fog applies + * @property user The _id of the User document to which this fog applies + * @property explored The base64 png image of the explored fog polygon + * @property positions The object of scene positions which have been explored at a certain vision radius + * @property timestamp The timestamp at which this fog exploration was last updated + */ + interface FogExplorationSource { + _id: string; + scene: string; + user: string; + explored: string; + position: unknown; + timestamp: number; + } } } diff --git a/types/foundry/common/documents/folder.d.ts b/types/foundry/common/documents/folder.d.ts index 4ffd5a5b036..d8cc35a572f 100644 --- a/types/foundry/common/documents/folder.d.ts +++ b/types/foundry/common/documents/folder.d.ts @@ -6,20 +6,44 @@ declare module foundry { * @param data Initial data from which to construct the document. * @property data The constructed data object for the document. */ - class BaseFolder extends abstract.Document { - static override get schema(): typeof data.FolderData; - + class BaseFolder extends abstract.Document { static override get metadata(): FolderMetadata; } - interface BaseFolder { - readonly data: data.FolderData; - - readonly parent: null; + interface BaseFolder extends abstract.Document { + readonly _source: FolderSource; get documentName(): (typeof BaseFolder)["metadata"]["name"]; } + /** + * The data schema for a Folder document. + * + * @param data Initial data used to construct the data object + * @param [document] The document to which this data object belongs + * + * @property _id The _id which uniquely identifies this Folder document + * @property name The name of this Folder + * @property type The document type which this Folder contains, from CONST.FOLDER_DOCUMENT_TYPES + * @property [description] An HTML description of the contents of this folder + * @property [parent] The _id of a parent Folder which contains this Folder + * @property [sorting=a] The sorting mode used to organize documents within this Folder, in ["a", "m"] + * @property [sort] The numeric sort value which orders this Folder relative to its siblings + * @property [color] A color string used for the background color of this Folder + * @property [flags={}] An object of optional key/value flags + */ + interface FolderSource { + _id: string; + name: string; + type: FolderDocumentType; + description: string; + parent: string | null; + sorting: "a" | "m"; + sort: number; + color: HexColorString; + flags: DocumentFlags; + } + interface FolderMetadata extends abstract.DocumentMetadata { name: "Folder"; collection: "folders"; diff --git a/types/foundry/common/documents/index.d.ts b/types/foundry/common/documents/index.d.ts index 6ea69505415..43ae9fde285 100644 --- a/types/foundry/common/documents/index.d.ts +++ b/types/foundry/common/documents/index.d.ts @@ -1,5 +1,6 @@ import "./active-effect"; import "./actor"; +import "./adventure"; import "./ambient-light"; import "./ambient-sound"; import "./cards"; diff --git a/types/foundry/common/documents/item.d.ts b/types/foundry/common/documents/item.d.ts index 59a889940b2..6c237a86e2b 100644 --- a/types/foundry/common/documents/item.d.ts +++ b/types/foundry/common/documents/item.d.ts @@ -1,7 +1,7 @@ declare module foundry { module documents { /** The Item document model. */ - class BaseItem extends abstract.Document { + class BaseItem extends abstract.Document { sort: number; /** The default icon used for newly created Item documents */ @@ -10,7 +10,7 @@ declare module foundry { static override get metadata(): ItemMetadata; /** A Collection of ActiveEffect embedded Documents */ - readonly effects: abstract.EmbeddedCollection; + readonly effects: abstract.EmbeddedCollection>; override canUserModify(user: BaseUser, action: UserAction, data?: DocumentUpdateData): boolean; @@ -40,16 +40,45 @@ declare module foundry { }): this["system"]; } - interface BaseItem { + interface BaseItem extends abstract.Document { flags: ItemFlags; - readonly _source: data.ItemSource; - readonly parent: BaseActor | null; + readonly _source: ItemSource; system: object; get documentName(): (typeof BaseItem)["metadata"]["name"]; } - interface ItemFlags { + /** + * The data schema for a Item document. + * @see BaseItem + * + * @param data Initial data used to construct the data object + * @param [document] The document to which this data object belongs + * + * @property _id The _id which uniquely identifies this Item document + * @property name The name of this Item + * @property type An Item subtype which configures the system data model applied + * @property [img] An image file path which provides the artwork for this Item + * @property [data] The system data object which is defined by the system template.json model + * @property folder The _id of a Folder which contains this Item + * @property [sort] The numeric sort value which orders this Item relative to its siblings + * @property [ownership] An object which configures user permissions to this Item + * @property [flags={}] An object of optional key/value flags + */ + interface ItemSource { + _id: string; + name: string; + type: TType; + img: ImageFilePath; + system: TSystemSource; + effects: ActiveEffectSource[]; + folder?: string | null; + sort: number; + ownership: Record; + flags: ItemFlags; + } + + interface ItemFlags extends DocumentFlags { core?: { sourceId?: ItemUUID; }; diff --git a/types/foundry/common/documents/journal-entry.d.ts b/types/foundry/common/documents/journal-entry.d.ts index dca9edae768..4b7292b0a4d 100644 --- a/types/foundry/common/documents/journal-entry.d.ts +++ b/types/foundry/common/documents/journal-entry.d.ts @@ -1,15 +1,13 @@ declare module foundry { module documents { /** The JournalEntry document model. */ - class BaseJournalEntry extends abstract.Document { + class BaseJournalEntry extends abstract.Document { static override get metadata(): JournalEntryMetadata; readonly pages: abstract.EmbeddedCollection>; } - interface BaseJournalEntry { - readonly parent: null; - + interface BaseJournalEntry extends abstract.Document { readonly _source: JournalEntrySource; get documentName(): (typeof BaseJournalEntry)["metadata"]["name"]; @@ -31,7 +29,7 @@ declare module foundry { * @property [permission] An object which configures user permissions to this JournalEntry * @property [flags={}] An object of optional key/value flags */ - interface JournalEntrySource extends abstract.DocumentSource { + interface JournalEntrySource { _id: string; name: string; pages: JournalEntryPageSource[]; diff --git a/types/foundry/common/documents/macro.d.ts b/types/foundry/common/documents/macro.d.ts index b3e52e7972b..c7b3b483cd6 100644 --- a/types/foundry/common/documents/macro.d.ts +++ b/types/foundry/common/documents/macro.d.ts @@ -1,32 +1,43 @@ declare module foundry { module documents { /** The Macro document model. */ - class BaseMacro extends abstract.Document { - static override get schema(): typeof data.MacroData; - + class BaseMacro extends abstract.Document { static override get metadata(): MacroMetadata; protected override _preCreate( - data: PreDocumentId, - options: DocumentModificationContext, + data: PreDocumentId, + options: DocumentModificationContext, user: BaseUser ): Promise; /** Is a user able to update an existing Macro document? */ - protected static _canUpdate(user: BaseUser, doc: BaseMacro, data: data.MacroData): boolean; + protected static _canUpdate(user: BaseUser, doc: BaseMacro, data: MacroSource): boolean; /** Is a user able to delete an existing Macro document? */ protected static _canDelete(user: BaseUser, doc: BaseMacro): boolean; } - interface BaseMacro { - readonly data: data.MacroData; - - readonly parent: null; + interface BaseMacro extends abstract.Document { + readonly _source: MacroSource; get documentName(): (typeof BaseMacro)["metadata"]["name"]; } + interface MacroSource { + _id: string; + name: string; + type: "chat" | "script"; + img: ImageFilePath; + actorIds: string[]; + author: string; + command: string; + scope: string; + folder?: string | null; + sort: number; + ownership: Record; + flags: DocumentFlags; + } + interface MacroMetadata extends abstract.DocumentMetadata { name: "Macro"; collection: "macros"; diff --git a/types/foundry/common/documents/measured-template.d.ts b/types/foundry/common/documents/measured-template.d.ts index b2864ae3636..ea7aab03720 100644 --- a/types/foundry/common/documents/measured-template.d.ts +++ b/types/foundry/common/documents/measured-template.d.ts @@ -1,11 +1,14 @@ declare module foundry { module documents { /** The MeasuredTemplate embedded document model. */ - class BaseMeasuredTemplate extends abstract.Document { - static override get schema(): typeof data.MeasuredTemplateData; - + class BaseMeasuredTemplate extends abstract.Document { static override get metadata(): MeasuredTemplateMetadata; + readonly t: MeasuredTemplateType; + width: number; + distance: number; + direction: number; + override testUserPermission( user: documents.BaseUser, permission: DocumentOwnershipString | DocumentOwnershipLevel, @@ -15,25 +18,51 @@ declare module foundry { /** Is a user able to update or delete an existing MeasuredTemplate? */ protected static _canModify( user: BaseUser, - doc: BaseMeasuredTemplate, - data: data.MeasuredTemplateData + doc: BaseMeasuredTemplate, + data: MeasuredTemplateSource ): boolean; } - interface BaseMeasuredTemplate { - readonly data: data.MeasuredTemplateData; - - readonly parent: BaseScene | null; - - readonly author: documents.BaseUser | undefined; - - readonly t: MeasuredTemplateType; - - width: number; + interface BaseMeasuredTemplate + extends abstract.Document, + MeasuredTemplateSource { + readonly _source: MeasuredTemplateSource; + } + /** + * The data schema for a MeasuredTemplate embedded document. + * @see BaseMeasuredTemplate + * + * @param data Initial data used to construct the data object + * @param [document] The embedded document to which this data object belongs + * + * @property _id The _id which uniquely identifies this BaseMeasuredTemplate embedded document + * @property [t=circle] The value in CONST.MEASURED_TEMPLATE_TYPES which defines the geometry type of this template + * @property [x=0] The x-coordinate position of the origin of the template effect + * @property [y=0] The y-coordinate position of the origin of the template effect + * @property [distance] The distance of the template effect + * @property [direction=0] The angle of rotation for the measured template + * @property [angle=360] The angle of effect of the measured template, applies to cone types + * @property [width] The width of the measured template, applies to ray types + * @property [borderColor=#000000] A color string used to tint the border of the template shape + * @property [fillColor=#FF0000] A color string used to tint the fill of the template shape + * @property [texture] A repeatable tiling texture used to add a texture fill to the template shape + * @property [flags={}] An object of optional key/value flags + */ + interface MeasuredTemplateSource { + _id: string | null; + user: string; + t: MeasuredTemplateType; + x: number; + y: number; distance: number; - direction: number; + angle: number; + width: number; + borderColor: HexColorString; + fillColor: HexColorString; + texture: ImageFilePath; + flags: DocumentFlags; } interface MeasuredTemplateMetadata extends abstract.DocumentMetadata { diff --git a/types/foundry/common/documents/note.d.ts b/types/foundry/common/documents/note.d.ts index 1a07fdb1001..7d6a59544de 100644 --- a/types/foundry/common/documents/note.d.ts +++ b/types/foundry/common/documents/note.d.ts @@ -1,19 +1,53 @@ declare module foundry { module documents { /** The Note embedded document model. */ - class BaseNote extends abstract.Document { - static override get schema(): typeof data.NoteData; - + class BaseNote extends abstract.Document { static override get metadata(): NoteMetadata; /** Is a user able to update an existing Note? */ - protected static _canUpdate(user: BaseUser, doc: BaseNote, data: data.NoteData): boolean; + protected static _canUpdate(user: BaseUser, doc: BaseNote, data: NoteSource): boolean; } - interface BaseNote { - readonly data: data.NoteData; + interface BaseNote extends abstract.Document { + readonly _source: NoteSource; + } - readonly parent: BaseScene | null; + /** + * The data schema for a Note embedded document. + * @see BaseNote + * + * @param data Initial data used to construct the data object + * @param [document] The embedded document to which this data object belongs + * + * @property _id The _id which uniquely identifies this BaseNote embedded document + * @property [entryId=null] The _id of a JournalEntry document which this Note represents + * @property [x=0] The x-coordinate position of the center of the note icon + * @property [y=0] The y-coordinate position of the center of the note icon + * @property [icon] An image icon path used to represent this note + * @property [iconSize=40] The pixel size of the map note icon + * @property [iconTint] An optional color string used to tint the map note icon + * @property [text] Optional text which overrides the title of the linked Journal Entry + * @property [fontFamily=Signika] The font family used to display the text label on this note + * @property [fontSize=36] The font size used to display the text label on this note + * @property [textAnchor=1] A value in CONST.TEXT_ANCHOR_POINTS which defines where the text label anchors + * to the note icon. + * @property [textColor=#FFFFFF] The string that defines the color with which the note text is rendered + * @property [flags={}] An object of optional key/value flags + */ + interface NoteSource { + _id: string; + entryId: string | null; + x: number; + y: number; + icon: ImageFilePath; + iconSize: number; + iconTint: HexColorString; + text: string; + fontFamily: string; + fontSize: number; + textAnchor: number; + textColor: HexColorString; + flags: Record; } interface NoteMetadata extends abstract.DocumentMetadata { diff --git a/types/foundry/common/documents/playlist-sound.d.ts b/types/foundry/common/documents/playlist-sound.d.ts index c939cee864c..5838263bc18 100644 --- a/types/foundry/common/documents/playlist-sound.d.ts +++ b/types/foundry/common/documents/playlist-sound.d.ts @@ -1,22 +1,45 @@ declare module foundry { module documents { /** The PlaylistSound document model. */ - class BasePlaylistSound extends abstract.Document { - static override get schema(): typeof data.PlaylistSoundData; - + class BasePlaylistSound extends abstract.Document { static override get metadata(): PlaylistSoundMetadata; testUserPermission( - user: documents.BaseUser, + user: BaseUser, permission: DocumentOwnershipString | DocumentOwnershipLevel, { exact }?: { exact?: boolean } ): boolean; } - interface BasePlaylistSound { - readonly data: data.PlaylistSoundData; + interface BasePlaylistSound extends abstract.Document { + readonly _source: PlaylistSoundSource; + } - readonly parent: BasePlaylist | null; + /** + * The data schema for a PlaylistSound embedded document. + * @see BasePlaylistSound + * + * @param data Initial data used to construct the data object + * @param [document] The document to which this data object belongs + * + * @property _id The _id which uniquely identifies this PlaylistSound document + * @property name The name of this sound track + * @property path The audio file path that is played by this sound + * @property [playing=false] Is this sound currently playing? + * @property [repeat=false] Does this sound loop? + * @property [volume=0.5] The audio volume of the sound, from 0 to 1 + * @property [streaming=false] Does this audio file use the "large file streaming" mode? + * @property [flags={}] An object of optional key/value flags + */ + interface PlaylistSoundSource { + _id: string; + name: string; + path: string; + playing: boolean; + repeat: boolean; + volumn: number; + streaming: boolean; + flags: Record; } interface PlaylistSoundMetadata extends abstract.DocumentMetadata { diff --git a/types/foundry/common/documents/playlist.d.ts b/types/foundry/common/documents/playlist.d.ts index b6bd8c1ac81..13a8698b080 100644 --- a/types/foundry/common/documents/playlist.d.ts +++ b/types/foundry/common/documents/playlist.d.ts @@ -1,23 +1,46 @@ declare module foundry { module documents { /** The Playlist document model. */ - class BasePlaylist extends abstract.Document { - static override get schema(): typeof data.PlaylistData; - + class BasePlaylist extends abstract.Document { static override get metadata(): PlaylistMetadata; /** A reference to the Collection of PlaylistSound instances in the Playlist document, indexed by _id. */ - get sounds(): this["data"]["sounds"]; + readonly sounds: abstract.EmbeddedCollection>; } - interface BasePlaylist { - readonly data: data.PlaylistData; - - readonly parent: null; + interface BasePlaylist extends abstract.Document { + readonly _source: PlaylistSource; get documentName(): (typeof BasePlaylist)["metadata"]["name"]; } + /** + * The data schema for a Playlist document. + * @see BasePlaylist + * @property _id The _id which uniquely identifies this Playlist document + * @property name The name of this playlist + * @property sounds A Collection of PlaylistSounds embedded documents which belong to this playlist + * @property [mode=0] The playback mode for sounds in this playlist + * @property [playing=false] Is this playlist currently playing? + * @property folder The _id of a Folder which contains this playlist + * @property [sort] The numeric sort value which orders this playlist relative to its siblings + * @property [permission] An object which configures user permissions to this playlist + * @property [flags={}] An object of optional key/value flags + */ + interface PlaylistSource { + _id: string; + name: string; + sounds: PlaylistSoundSource[]; + mode: PlaylistMode; + playing: boolean; + fade: number; + folder: string; + sort: number; + seed: number; + permission: Record; + flags: Record; + } + interface PlaylistMetadata extends abstract.DocumentMetadata { name: "Playlist"; collection: "playlists"; diff --git a/types/foundry/common/documents/roll-table.d.ts b/types/foundry/common/documents/roll-table.d.ts index 80671d738f3..5e915b4c6ca 100644 --- a/types/foundry/common/documents/roll-table.d.ts +++ b/types/foundry/common/documents/roll-table.d.ts @@ -5,23 +5,54 @@ declare module foundry { * @param data Initial data from which to construct the document. * @property data The constructed data object for the document. */ - class BaseRollTable extends abstract.Document { - static override get schema(): typeof data.RollTableData; - + class BaseRollTable extends abstract.Document { static override get metadata(): RollTableMetadata; /** A reference to the Collection of TableResult instances in this document, indexed by _id. */ - get results(): this["data"]["results"]; + readonly results: abstract.EmbeddedCollection>; } - interface BaseRollTable { - readonly data: data.RollTableData; - - readonly parent: null; + interface BaseRollTable extends abstract.Document { + readonly _source: RollTableSource; get documentName(): (typeof BaseRollTable)["metadata"]["name"]; } + /** + * The data schema for a RollTable document. + * @see BaseRollTable + * + * @param data Initial data used to construct the data object + * @param [document] The document to which this data object belongs + * + * @property _id The _id which uniquely identifies this RollTable document + * @property name The name of this RollTable + * @property [img] An image file path which provides the thumbnail artwork for this RollTable + * @property [description] The HTML text description for this RollTable document + * @property [results=[]] A Collection of TableResult embedded documents which belong to this RollTable + * @property formula The Roll formula which determines the results chosen from the table + * @property [replacement=true] Are results from this table drawn with replacement? + * @property [displayRoll=true] Is the Roll result used to draw from this RollTable displayed in chat? + * @property folder The _id of a Folder which contains this RollTable + * @property [sort] The numeric sort value which orders this RollTable relative to its siblings + * @property [permission] An object which configures user permissions to this RollTable + * @property [flags={}] An object of optional key/value flags + */ + interface RollTableSource { + _id: string; + name: string; + img?: ImageFilePath; + description: string; + results: TableResultSource[]; + formula: string; + replacement: boolean; + displayRoll: boolean; + folder?: string | null; + sort: number; + ownership: Record; + flags: Record>; + } + interface RollTableMetadata extends abstract.DocumentMetadata { name: "RollTable"; collection: "tables"; diff --git a/types/foundry/common/documents/scene.d.ts b/types/foundry/common/documents/scene.d.ts index 74faf9fcaa5..b5d8c90573b 100644 --- a/types/foundry/common/documents/scene.d.ts +++ b/types/foundry/common/documents/scene.d.ts @@ -8,41 +8,41 @@ declare global { * @param data Initial data from which to construct the document. * @property data The constructed data object for the document. */ - class BaseScene extends abstract.Document { - grid: data.GridData; - + class BaseScene extends abstract.Document { + active: boolean; + background: data.TextureData; + grid: GridData; darkness: number; - tokenVision: boolean; - globalLight: boolean; - hasGlobalThreshold: boolean; - globalLightThreshold: number; - - flags: Record>; + flags: DocumentFlags; + playlist: BasePlaylist | null; + playlistSound: string | null; + journal: BaseJournalEntry | null; + journalEntryPage: string | null; /** A reference to the Collection of Drawing instances in the Scene document, indexed by _id. */ - readonly drawings: abstract.EmbeddedCollection; + readonly drawings: abstract.EmbeddedCollection>; /** A reference to the Collection of AmbientLight instances in the Scene document, indexed by _id. */ - readonly lights: abstract.EmbeddedCollection; + readonly lights: abstract.EmbeddedCollection>; /** A reference to the Collection of Note instances in the Scene document, indexed by _id. */ - readonly notes: abstract.EmbeddedCollection; + readonly notes: abstract.EmbeddedCollection>; /** A reference to the Collection of AmbientSound instances in the Scene document, indexed by _id. */ - readonly sounds: abstract.EmbeddedCollection; + readonly sounds: abstract.EmbeddedCollection>; /** A reference to the Collection of MeasuredTemplate instances in the Scene document, indexed by _id. */ - readonly templates: abstract.EmbeddedCollection; + readonly templates: abstract.EmbeddedCollection>; /** A reference to the Collection of Token instances in the Scene document, indexed by _id. */ - readonly tokens: abstract.EmbeddedCollection; + readonly tokens: abstract.EmbeddedCollection>; /** A reference to the Collection of Tile instances in the Scene document, indexed by _id. */ - readonly tiles: abstract.EmbeddedCollection; + readonly tiles: abstract.EmbeddedCollection>; /** A reference to the Collection of Wall instances in the Scene document, indexed by _id. */ readonly walls: abstract.EmbeddedCollection>; @@ -65,12 +65,86 @@ declare global { }: GetDimensionsParams): SceneDimensions; } - interface BaseScene { - readonly data: data.SceneData; + interface BaseScene extends foundry.abstract.Document { + readonly _source: SceneSource; + get documentName(): (typeof BaseScene)["metadata"]["name"]; + } + + interface SceneSource { + _id: string; + name: string; + + // Navigation + active: boolean; + navigation: boolean; + navOrder: number; + navName: string; + + // Canvas Dimensions + img: VideoFilePath; + foreground: VideoFilePath; + thumb: ImageFilePath; + width: number; + height: number; + padding: number; + initial: { + x: number; + y: number; + scale: number; + }; - readonly parent: null; + backgroundColor: HexColorString; - get documentName(): (typeof BaseScene)["metadata"]["name"]; + grid: GridData; + + shiftX: number; + shiftY: number; + + // Vision and Lighting Configuration + tokenVision: boolean; + fogExploration: boolean; + fogReset: string; + globalLight: boolean; + globalLightThreshold: number; + hasGlobalThreshold: boolean; + darkness: number; + + // Embedded Collections + drawings: DrawingSource[]; + tokens: TokenSource[]; + lights: AmbientLightSource[]; + notes: NoteSource[]; + sounds: AmbientSoundSource[]; + templates: MeasuredTemplateSource[]; + tiles: TileSource[]; + walls: WallSource[]; + + // Linked Documents + playlist: PlaylistSource | null; + playlistSound: PlaylistSoundSource | null; + journal: JournalEntrySource | null; + weather: string; + + // Permissions + folder: string | null; + sort: number; + ownership: Record; + flags: Record>; + } + + interface GridData { + /** The type of grid, a number from CONST.GRID_TYPES. */ + type: GridType; + /** The grid size which represents the width (or height) of a single grid space. */ + size: number; + /** A string representing the color used to render the grid lines. */ + color: HexColorString; + /** A number between 0 and 1 for the opacity of the grid lines. */ + alpha: number; + /** The number of distance units which are represented by a single grid space. */ + distance: number; + /** A label for the units of measure which are used for grid distance. */ + units: string; } interface SceneMetadata extends abstract.DocumentMetadata { @@ -95,7 +169,8 @@ declare global { /** * @property [isUndo] Is the operation undoing a previous operation, only used by embedded Documents within a Scene */ - interface SceneEmbeddedModificationContext extends DocumentModificationContext { + interface SceneEmbeddedModificationContext + extends DocumentModificationContext { isUndo?: boolean; } diff --git a/types/foundry/common/documents/table-result.d.ts b/types/foundry/common/documents/table-result.d.ts index be5734ae70b..69ea92c02e0 100644 --- a/types/foundry/common/documents/table-result.d.ts +++ b/types/foundry/common/documents/table-result.d.ts @@ -1,13 +1,15 @@ declare module foundry { module documents { /** The TableResult document model. */ - class BaseTableResult extends abstract.Document { - static override get schema(): typeof data.RollTableData; - + class BaseTableResult extends abstract.Document { static override get metadata(): TableResultMetadata; /** Is a user able to update an existing TableResult? */ - protected static _canUpdate(user: BaseUser, doc: BaseTableResult, data: data.TableResultData): boolean; + protected static _canUpdate( + user: BaseUser, + doc: BaseTableResult, + data: TableResultSource + ): boolean; override testUserPermission( user: BaseUser, @@ -16,10 +18,36 @@ declare module foundry { ): boolean; } - interface BaseTableResult { - readonly data: data.TableResultData; + interface BaseTableResult extends abstract.Document { + readonly _source: TableResultSource; + } - readonly parent: BaseRollTable | null; + /** + * The data schema for a TableResult embedded document within a Roll Table. + * @see BaseTableResult + * + * @param data Initial data used to construct the data object + * @param [document] The document to which this data object belongs + * + * @property [type=p] A result sub-type from CONST.TABLE_RESULT_TYPES + * @property [text] The text which describes the table result + * @property [img] An image file url that represents the table result + * @property [collection] A named collection from which this result is drawn + * @property [resultId] The _id of a Document within the collection this result references + * @property [weight=1] The probabilistic weight of this result relative to other results + * @property [range] A length 2 array of ascending integers which defines the range of dice roll + * totals which produce this drawn result + * @property [drawn=false] Has this result already been drawn (without replacement) + */ + interface TableResultSource { + type: TableResultType; + text: string; + img: ImageFilePath; + collection: string; + resultId: string; + weight: number; + range: [number, number]; + drawn: boolean; } interface TableResultMetadata extends abstract.DocumentMetadata { diff --git a/types/foundry/common/documents/tile.d.ts b/types/foundry/common/documents/tile.d.ts index 7e6d2035b0e..9fd92f03150 100644 --- a/types/foundry/common/documents/tile.d.ts +++ b/types/foundry/common/documents/tile.d.ts @@ -1,16 +1,52 @@ declare module foundry { module documents { /** The Tile embedded document model. */ - class BaseTile extends abstract.Document { - static override get schema(): typeof data.TileData; - + class BaseTile extends abstract.Document { static override get metadata(): TileMetadata; } - interface BaseTile { - readonly data: data.TileData; + interface BaseTile extends abstract.Document { + readonly _source: TileSource; + } - readonly parent: BaseScene | null; + /** + * The data schema for a Tile embedded document. + * @see BaseTile + * + * @property _id The _id which uniquely identifies this Tile embedded document + * @property [img] An image or video file path which this tile displays + * @property [width=0] The pixel width of the tile + * @property [height=0] The pixel height of the tile + * @property [x=0] The x-coordinate position of the top-left corner of the tile + * @property [y=0] The y-coordinate position of the top-left corner of the tile + * @property [z=100] The z-index ordering of this tile relative to its siblings + * @property [rotation=0] The angle of rotation for the tile between 0 and 360 + * @property [alpha=1] The tile opacity + * @property [tint] A color to tint the tile + * @property [hidden=false] Is the tile currently hidden? + * @property [locked=false] Is the tile currently locked? + * @property [overhead=false] Is the tile an overhead tile? + * @property [occlusion] The tile's occlusion settings + * @property [video] The tile's video settings + * @property [flags={}] An object of optional key/value flags + */ + interface TileSource { + _id: string; + img: ImageFilePath | null; + width: number; + height: number; + x: number; + y: number; + z: number; + rotation: number; + alpha: number; + tint: HexColorString | null; + hidden: boolean; + locked: boolean; + overhead: boolean; + video: data.VideoData; + occlusion: data.TileOcclusion; + flags: DocumentFlags; } interface TileMetadata extends abstract.DocumentMetadata { diff --git a/types/foundry/common/documents/token.d.ts b/types/foundry/common/documents/token.d.ts index 89c7d99eac9..c1d51f0c246 100644 --- a/types/foundry/common/documents/token.d.ts +++ b/types/foundry/common/documents/token.d.ts @@ -5,7 +5,7 @@ declare module foundry { * @param data Initial data from which to construct the document. * @property data The constructed data object for the document. */ - class BaseToken extends abstract.Document { + class BaseToken extends abstract.Document { readonly actorLink: boolean; displayName: TokenDisplayMode; @@ -26,7 +26,7 @@ declare module foundry { tint: HexColorString; }; - light: foundry.data.LightData; + light: foundry.data.LightData; sight: { enabled: boolean; @@ -44,18 +44,114 @@ declare module foundry { effects: VideoFilePath[]; - static override get schema(): typeof data.TokenData; + flags: DocumentFlags; static override get metadata(): TokenMetadata; /** Is a user able to update an existing Token? */ - protected static _canUpdate(user: BaseUser, doc: BaseToken, data: data.TokenData): boolean; + protected static _canUpdate(user: BaseUser, doc: BaseToken, data: TokenSource): boolean; } - interface BaseToken extends abstract.Document { - readonly data: data.TokenData; + interface BaseToken extends abstract.Document { + readonly _source: TokenSource; + } + + /** + * The data schema for a Token document. + * + * @property _id The Token _id which uniquely identifies it within its parent Scene + * @property name The name used to describe the Token + * @property [displayName=0] The display mode of the Token nameplate, from CONST.TOKEN_DISPLAY_MODES + * @property actorId The _id of an Actor document which this Token represents + * @property [actorLink=false] Does this Token uniquely represent a singular Actor, or is it one of many? + * @property [actorData] Token-level data which overrides the base data of the associated Actor + * @property [width=1] The width of the Token in grid units + * @property [height=1] The height of the Token in grid units + * @property [scale=1] A scale factor applied to the Token image, between 0.25 and 3 + * @property [mirrorX=false] Flip the Token image horizontally? + * @property [mirrorY=false] Flip the Token image vertically? + * @property [x=0] The x-coordinate of the top-left corner of the Token + * @property [y=0] The y-coordinate of the top-left corner of the Token + * @property [elevation=0] The vertical elevation of the Token, in distance units + * @property [lockRotation=false] Prevent the Token image from visually rotating? + * @property [rotation=0] The rotation of the Token in degrees, from 0 to 360. A value of 0 represents a southward-facing Token. + * @property [effects] An array of effect icon paths which are displayed on the Token + * @property [overlayEffect] A single icon path which is displayed as an overlay on the Token + * @property [hidden=false] Is the Token currently hidden from player view? + * @property [vision] Is this Token a source of vision? + * @property [dimSight=0] How far in distance units the Token can naturally see as if in dim light + * @property [brightSight=0] How far in distance units the Token can naturally see as if in bright light + * @property [sightAngle=360] The angle at which this Token is able to see, if it has vision + * @property [light] The angle at which this Token is able to see, if it has vision + * @property [dimLight=0] How far in distance units this Token emits dim light + * @property [brightLight=0] How far in distance units this Token emits bright light + * @property [lightAngle=360] The angle at which this Token is able to emit light + * @property [lightAnimation] A data object which configures token light animation settings + * @property [disposition=-1] A displayed Token disposition from CONST.TOKEN_DISPOSITIONS + * @property [displayBars=0] The display mode of Token resource bars, from CONST.TOKEN_DISPLAY_MODES + * @property [bar1] The configuration of the Token's primary resource bar + * @property [bar2] The configuration of the Token's secondary resource bar + * @property [flags={}] An object of optional key/value flags + */ + interface TokenSource extends TokenLightData { + _id: string; + name: string; - readonly parent: BaseScene | null; + // Navigation + active: boolean; + navigation: boolean; + navOrder: number; + navName: string; + + actorId: string | null; + actorLink: boolean; + actorData: DeepPartial; + mirrorX: boolean; + mirrorY: boolean; + height: number; + width: number; + x: number; + y: number; + elevation: number; + lockRotation: boolean; + effects: VideoFilePath[]; + overlayEffect: string | null; + vision: boolean; + dimSight: number; + brightSight: number; + sightAngle: number; + light: data.LightSource; + hidden: boolean; + texture: { + src: VideoFilePath; + scaleX: number; + scaleY: number; + offsetX: number; + offsetY: number; + rotation: number | null; + tint: `#${string}`; + }; + + lightAnimation: data.AnimationData; + disposition: TokenDisposition; + displayName: TokenDisplayMode; + displayBars: TokenDisplayMode; + bar1: TokenBarData; + bar2: TokenBarData; + flags: DocumentFlags; + } + + interface TokenLightData { + brightLight: number; + dimLight: number; + lightAlpha: number; + lightAngle: number; + lightAnimation: { + type: string; + speed: number; + intensity: number; + }; + lightColor: string; } interface TokenMetadata extends abstract.DocumentMetadata { @@ -67,5 +163,13 @@ declare module foundry { create: "TOKEN_CREATE"; }; } + + /** + * An embedded data structure for the contents of a Token attribute bar. + * @property [attribute] The attribute path within the Token's Actor data which should be displayed + */ + interface TokenBarData { + attribute: string | null; + } } } diff --git a/types/foundry/common/documents/user.d.ts b/types/foundry/common/documents/user.d.ts index 4ee5a5ff597..2999d85bb73 100644 --- a/types/foundry/common/documents/user.d.ts +++ b/types/foundry/common/documents/user.d.ts @@ -8,17 +8,15 @@ declare module foundry { * @param data Initial data from which to construct the document. * @property data The constructed data object for the document. */ - class BaseUser extends abstract.Document { - flags: DocumentFlags; - - readonly role: UserRole; - - name: string; + class BaseUser extends abstract.Document { avatar: ImageFilePath; - color: HexColorString; - charname: string; - character: BaseActor | null | undefined; border: HexColorString; + character: BaseActor | null | undefined; + charname: string; + color: HexColorString; + flags: DocumentFlags; + name: string; + readonly role: UserRole; static override get metadata(): UserMetadata; @@ -57,16 +55,12 @@ declare module foundry { hasRole(role: UserRole | UserRoleName, { exact }?: { exact: boolean }): boolean; } - interface BaseUser extends abstract.Document { - readonly parent: null; + interface BaseUser extends abstract.Document { + readonly _source: UserSource; get documentName(): "User"; } - class UserData extends abstract.DocumentData { - readonly _source: UserSource; - } - interface UserMetadata extends abstract.DocumentMetadata { name: "User"; collection: "users"; diff --git a/types/foundry/common/documents/wall.d.ts b/types/foundry/common/documents/wall.d.ts index 2fecf7af284..7f48756560c 100644 --- a/types/foundry/common/documents/wall.d.ts +++ b/types/foundry/common/documents/wall.d.ts @@ -1,13 +1,11 @@ declare module foundry { module documents { /** The Wall embedded document model. */ - class BaseWall extends abstract.Document { - static override get schema(): typeof data.WallData; - + class BaseWall extends abstract.Document { static override get metadata(): WallMetadata; /** Is a user able to update an existing Wall? */ - protected static _canUpdate(user: BaseUser, doc: BaseWall, data: data.WallData): boolean; + protected static _canUpdate(user: BaseUser, doc: BaseWall, data: WallSource): boolean; light: WallSenseType; move: WallSenseType; @@ -15,9 +13,17 @@ declare module foundry { sound: WallSenseType; } - interface BaseWall { - readonly data: data.WallData; - readonly parent: TParent; + interface BaseWall extends abstract.Document { + readonly _source: WallSource; + } + + interface WallSource { + c: number[]; + move?: number; + sense?: number; + dir?: number; + door?: number; + ds?: number; } interface WallMetadata extends abstract.DocumentMetadata { diff --git a/types/foundry/common/utils/helpers.d.ts b/types/foundry/common/utils/helpers.d.ts index 4b7edd4f3f3..b254a273c1f 100644 --- a/types/foundry/common/utils/helpers.d.ts +++ b/types/foundry/common/utils/helpers.d.ts @@ -29,8 +29,6 @@ declare global { * For a subset of cases the deepClone function will offer better performance. * @param original Some sort of data */ - function duplicate(original: T): T["data"]; - function duplicate(original: T): RawObject; function duplicate(original: T): T; /** diff --git a/types/foundry/index.d.ts b/types/foundry/index.d.ts index 455374c3531..16573f63547 100644 --- a/types/foundry/index.d.ts +++ b/types/foundry/index.d.ts @@ -1,28 +1,7 @@ import "./client/application/base"; import "./client/application/chat-popout"; import "./client/application/compendium"; -import "./client/application/form-application/base"; -import "./client/application/form-application/client-settings"; -import "./client/application/form-application/document-sheet-config"; -import "./client/application/form-application/document-sheet/active-effect-config"; -import "./client/application/form-application/document-sheet/actor-sheet"; -import "./client/application/form-application/document-sheet/base"; -import "./client/application/form-application/document-sheet/combatant-config"; -import "./client/application/form-application/document-sheet/item-sheet"; -import "./client/application/form-application/document-sheet/journal-page-sheet"; -import "./client/application/form-application/document-sheet/journal-sheet"; -import "./client/application/form-application/document-sheet/macro-config"; -import "./client/application/form-application/document-sheet/note-config"; -import "./client/application/form-application/document-sheet/scene-config"; -import "./client/application/form-application/document-sheet/user-config"; -import "./client/application/form-application/document-sheet/wall-config"; -import "./client/application/form-application/image-popout"; -import "./client/application/form-application/other"; -import "./client/application/form-application/permission"; -import "./client/application/form-application/placeables-config"; -import "./client/application/form-application/roll-table-config"; -import "./client/application/form-application/tile-config"; -import "./client/application/form-application/token-config"; +import "./client/application/form-application"; import "./client/application/hotbar"; import "./client/application/hud/chat-bubbles"; import "./client/application/hud/container"; @@ -88,9 +67,6 @@ import "./client/pixi/placeable-object/wall"; import "./client/pixi/placeables-layer/base"; import "./client/pixi/placeables-layer/drawings-layer"; import "./client/pixi/placeables-layer/lighting-layer"; -import "./client/pixi/placeables-layer/map-layer/background-layer"; -import "./client/pixi/placeables-layer/map-layer/base"; -import "./client/pixi/placeables-layer/map-layer/foreground-layer"; import "./client/pixi/placeables-layer/notes-layer"; import "./client/pixi/placeables-layer/sounds-layer"; import "./client/pixi/placeables-layer/template-layer"; diff --git a/types/foundry/package.json b/types/foundry/package.json index 3d31b587803..2f7f4434a58 100644 --- a/types/foundry/package.json +++ b/types/foundry/package.json @@ -18,6 +18,5 @@ }, "author": "the pf2e system developers", "license": "Apache-2.0", - "type": "module", "types": "./index.d.ts" } diff --git a/types/foundry/client/documents/mixins/client-document-mixin2.d.ts b/types/foundry/scripts/generate-client-base-mixes.ts similarity index 70% rename from types/foundry/client/documents/mixins/client-document-mixin2.d.ts rename to types/foundry/scripts/generate-client-base-mixes.ts index 99ffdbd908d..650dbf3578c 100644 --- a/types/foundry/client/documents/mixins/client-document-mixin2.d.ts +++ b/types/foundry/scripts/generate-client-base-mixes.ts @@ -1,7 +1,24 @@ -/** System note: refactored `ClientDocument` mixin typing approach in testing */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -declare class ClientDocument2 | null = ClientDocument2 | null> extends foundry - .abstract.Document { +type ParentData = { name: string; hasParents: boolean }; + +const genClientBase = ( + className: string, + { + hasSheet = true, + isCanvasDoc = false, + parents = isCanvasDoc ? [{ name: "Scene", hasParents: false }] : [], + }: { hasSheet?: boolean; isCanvasDoc?: boolean; parents?: ParentData[] } +) => { + const declareOrExportClientBase = isCanvasDoc ? "declare" : "export"; + const clientBaseName = `ClientBase${className}`; + const typeParamName = parents + .map((p) => (p.hasParents ? `ClientBase${p.name}` : `ClientBase${p.name}`)) + .join(" | "); + const typeParams = typeParamName ? `` : ""; + const tParentOrBlank = typeParamName ? "" : ""; + const tParentOrNull = typeParamName ? "TParent" : "null"; + console.log(String.raw`${declareOrExportClientBase} class ${clientBaseName}${typeParams} extends foundry.documents.Base${className}${tParentOrBlank} { + protected _sheet: FormApplication | null; + /** * A collection of Application instances which should be re-rendered whenever this document is updated. * The keys of this object are the application ids and the values are Application instances. Each @@ -10,10 +27,11 @@ declare class ClientDocument2 | null = Clie */ apps: { [K in number]?: Application }; - constructor(data: object, context: DocumentConstructionContext); + constructor(data: object, context?: DocumentConstructionContext<${tParentOrNull}>); static override name: string; + protected override _initialize(options?: Record): void; /* -------------------------------------------- */ @@ -46,16 +64,16 @@ declare class ClientDocument2 | null = Clie * See the CONST.DOCUMENT_OWNERSHIP_LEVELS object for an enumeration of these levels. * * @example Get the permission level the current user has for a document - * ```js + * \`\`\`js * game.user.id; // "dkasjkkj23kjf" * actor.data.permission; // {default: 1, "dkasjkkj23kjf": 2}; * actor.permission; // 2 - * ``` + * \`\`\` */ get permission(): DocumentOwnershipLevel; /** Lazily obtain a FormApplication instance used to configure this Document, or null if no sheet is available. */ - get sheet(): FormApplication | null; + get sheet(): ${hasSheet ? "FormApplication" : "null"}; /** A Universally Unique Identifier (uuid) for this Document instance. */ get uuid(): DocumentUUID; @@ -119,7 +137,7 @@ declare class ClientDocument2 | null = Clie * @param doc The document to compare against. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any - getRelativeUUID(doc: ClientDocument2): string; + getRelativeUUID(doc: foundry.abstract.Document): string; /** * Handle clicking on a content link for this document. @@ -133,17 +151,17 @@ declare class ClientDocument2 | null = Clie protected override _onCreate( data: this["_source"], - options: DocumentModificationContext, + options: DocumentModificationContext<${tParentOrNull}>, userId: string ): void; protected override _onUpdate( data: DeepPartial, - options: DocumentModificationContext, + options: DocumentModificationContext<${tParentOrNull}>, userId: string ): void; - protected override _onDelete(options: DocumentModificationContext, userId: string): void; + protected override _onDelete(options: DocumentModificationContext<${tParentOrNull}>, userId: string): void; /** * Preliminary actions taken before a set of embedded Documents in this parent Document are created. @@ -169,7 +187,7 @@ declare class ClientDocument2 | null = Clie */ protected _onCreateEmbeddedDocuments( embeddedName: string, - documents: ClientDocument2[], + documents: foundry.abstract.Document[], result: object[], options: DocumentModificationContext, userId: string @@ -199,7 +217,7 @@ declare class ClientDocument2 | null = Clie */ protected _onUpdateEmbeddedDocuments( embeddedName: string, - documents: ClientDocument2[], + documents: foundry.abstract.Document[], result: object, options: DocumentUpdateContext, userId: string @@ -229,7 +247,7 @@ declare class ClientDocument2 | null = Clie */ protected _onDeleteEmbeddedDocuments( embeddedName: string, - documents: ClientDocument[], + documents: foundry.abstract.Document[], result: string[], options: DocumentModificationContext, userId: string @@ -249,18 +267,14 @@ declare class ClientDocument2 | null = Clie * @param [context={}] Additional context options or dialog positioning options * @returns A Promise which resolves to the created Document, or null if the dialog was closed. */ - static createDialog( + static createDialog( + this: ConstructorOf, data?: Record, - { - parent, - pack, - ...options - }?: { - parent: ClientDocument | null; - pack: CompendiumCollection | null; - options?: Record; - } - ): Promise | null>; + context?: { + parent?: TDocument["parent"]; + pack?: Collection | null; + } & Partial + ): Promise; /** * Present a Dialog form to confirm deletion of this Document. @@ -303,14 +317,17 @@ declare class ClientDocument2 | null = Clie * The dropped data could have: * 1. A data object explicitly provided * 2. A UUID - * @memberof ClientDocumentMixin * * @param data The data object extracted from a DataTransfer event * @param options Additional options which affect drop data behavior * @returns The resolved Document * @throws If a Document could not be retrieved from the provided data. */ - static fromDropData(data?: object, options?: Record): Promise; + static fromDropData( + this: ConstructorOf, + data?: object, + options?: Record + ): Promise; /** * Update this Document using a provided JSON string. @@ -345,26 +362,109 @@ declare class ClientDocument2 | null = Clie } ): this["_source"]; } +`); + + if (isCanvasDoc) { + const canvasBaseName = `CanvasBase${className}`; + + console.log(String.raw`/** + * A specialized sub-class of the ClientDocumentMixin which is used for document types that are intended to be + * represented upon the game Canvas. + * @category - Mixins + */ +export class ${canvasBaseName}< + TParent extends ClientBaseScene | null +> extends ${clientBaseName} { + /** A reference to the PlaceableObject instance which represents this Embedded Document. */ + _object: PlaceableObject | null; + + /** Has this object been deliberately destroyed as part of the deletion workflow? */ + protected _destroyed: boolean; + + constructor(data: object, context: DocumentConstructionContext); + + /* -------------------------------------------- */ + /* Properties */ + /* -------------------------------------------- */ + + /** A lazily constructed PlaceableObject instance which can represent this Document on the game canvas. */ + get object(): this["_object"]; + + /** A reference to the CanvasLayer which contains Document objects of this type. */ + get layer(): NonNullable["layer"] | null; + + /** An indicator for whether this document is currently rendered on the game canvas. */ + get rendered(): boolean; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -declare interface ClientDocument2 | null = ClientDocument2 | null> - extends foundry.abstract.Document { - readonly parent: TParent; + /* -------------------------------------------- */ + /* Event Handlers */ + /* -------------------------------------------- */ + + /** + * @see abstract.Document#_onCreate + */ + protected override _onCreate(data: this["_source"], options: DocumentModificationContext, userId: string): void; + + /** + * @see abstract.Document#_onUpdate + */ + protected override _onUpdate( + changed: DeepPartial, + options: DocumentUpdateContext, + userId: string + ): void; + + /** + * @see abstract.Document#_onDelete + */ + protected _onDelete(options: DocumentModificationContext, userId: string): void; } -type BaseDocumentWithOmissions = Omit< - TDocument, - | "_initialize" - | "_source" - | "clone" - | "delete" - | "documentName" - | "getUserLevel" - | "parent" - | "setFlag" - | "toJSON" - | "toObject" - | "unsetFlag" - | "update" - | "updateSource" ->; +export interface ${canvasBaseName}< + TParent extends ClientBaseScene | null +> extends ${clientBaseName} { + // System note: in most but not all canvas documents + hidden?: boolean; +} +`); + } +}; + +const clientDocs: Record = { + AmbientLight: { isCanvasDoc: true }, + AmbientSound: { isCanvasDoc: true }, + ActiveEffect: { + parents: [ + { name: "Actor", hasParents: true }, + { name: "Item", hasParents: true }, + ], + }, + Actor: { parents: [{ name: "Token", hasParents: true }] }, + Adventure: {}, + Cards: {}, + ChatMessage: {}, + Combat: {}, + Combatant: { parents: [{ name: "Combat", hasParents: false }] }, + Drawing: { isCanvasDoc: true }, + FogExploration: { hasSheet: false }, + Folder: {}, + Item: { parents: [{ name: "Actor", hasParents: true }] }, + JournalEntry: {}, + JournalEntryPage: { parents: [{ name: "JournalEntry", hasParents: false }] }, + Macro: {}, + MeasuredTemplate: { isCanvasDoc: true }, + Note: { isCanvasDoc: true }, + Playlist: {}, + PlaylistSound: { parents: [{ name: "Playlist", hasParents: false }] }, + RollTable: {}, + Scene: {}, + TableResult: { parents: [{ name: "RollTable", hasParents: false }] }, + Tile: { isCanvasDoc: true }, + Token: { isCanvasDoc: true }, + User: {}, + Wall: { isCanvasDoc: true }, +}; + +for (const [className, data] of Object.entries(clientDocs)) { + genClientBase(className, data); +} diff --git a/types/foundry/tsconfig.json b/types/foundry/tsconfig.json index e5ba04ca989..700f53ac18b 100644 --- a/types/foundry/tsconfig.json +++ b/types/foundry/tsconfig.json @@ -9,7 +9,8 @@ ], "strict": true, "noImplicitOverride": true, - "noEmit": true + "noEmit": true, + "esModuleInterop": true }, "files": [ "index.d.ts", diff --git a/types/foundry/util.d.ts b/types/foundry/util.d.ts index b8c0968ffbb..37eefcef16b 100644 --- a/types/foundry/util.d.ts +++ b/types/foundry/util.d.ts @@ -22,6 +22,12 @@ declare global { // eslint-disable-next-line @typescript-eslint/no-explicit-any type ConstructorOf = new (...args: any[]) => T; + type DocumentConstructorOf = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + new (...args: any[]): T; + updateDocuments(updates?: object[], context?: DocumentModificationContext): Promise; + }; + type ParentOf = TDataModel extends DataModel ? P : never; type SchemaOf = TDataModel extends DataModel ? S : never; @@ -29,4 +35,8 @@ declare global { type SetElement> = TSet extends Set ? TElement : never; type DropFirst = T extends [unknown, ...infer U] ? U : never; + + type TypeParamOf = T extends TypeWithGeneric ? U : never; } + +type TypeWithGeneric = T[];