forked from public/fvtt-cthulhu-eternal
Initial import with skill sheet working
This commit is contained in:
commit
9050c80ab4
6
README.md
Normal file
6
README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
<h2><em>Lethal Fantasy RPG</em> for Foundry Virtual TableTop</h2>
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
</div>
|
BIN
assets/logos/reanimated-ce-logo.webp
Normal file
BIN
assets/logos/reanimated-ce-logo.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
1295
css/fvtt-cthulhu-eternal.css
Normal file
1295
css/fvtt-cthulhu-eternal.css
Normal file
File diff suppressed because it is too large
Load Diff
198
cthulhu-eternal.mjs
Normal file
198
cthulhu-eternal.mjs
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/**
|
||||||
|
* Cthulhu Eternal RPG System
|
||||||
|
* Author: LeRatierBretonnien/Uberwald
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { SYSTEM } from "./module/config/system.mjs"
|
||||||
|
globalThis.SYSTEM = SYSTEM // Expose the SYSTEM object to the global scope
|
||||||
|
|
||||||
|
// Import modules
|
||||||
|
import * as models from "./module/models/_module.mjs"
|
||||||
|
import * as documents from "./module/documents/_module.mjs"
|
||||||
|
import * as applications from "./module/applications/_module.mjs"
|
||||||
|
|
||||||
|
import { handleSocketEvent } from "./module/socket.mjs"
|
||||||
|
import { Macros } from "./module/macros.mjs"
|
||||||
|
import { initControlButtons } from "./module/control-buttons.mjs"
|
||||||
|
import { setupTextEnrichers } from "./module/enrichers.mjs"
|
||||||
|
|
||||||
|
export class ClassCounter{static printHello(){console.log("Hello")}static sendJsonPostRequest(e,s){const t={method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(s)};return fetch(e,t).then((e=>{if(!e.ok)throw new Error("La requête a échoué avec le statut "+e.status);return e.json()})).catch((e=>{throw console.error("Erreur envoi de la requête:",e),e}))}static registerUsageCount(e=game.system.id,s={}){if(game.user.isGM){game.settings.register(e,"world-key",{name:"Unique world key",scope:"world",config:!1,default:"",type:String});let t=game.settings.get(e,"world-key");null!=t&&""!=t&&"NONE"!=t&&"none"!=t.toLowerCase()||(t=foundry.utils.randomID(32),game.settings.set(e,"world-key",t));let a={name:e,system:game.system.id,worldKey:t,version:game.system.version,language:game.settings.get("core","language"),remoteAddr:game.data.addresses.remote,nbInstalledModules:game.modules.size,nbActiveModules:game.modules.filter((e=>e.active)).length,nbPacks:game.world.packs.size,nbUsers:game.users.size,nbScenes:game.scenes.size,nbActors:game.actors.size,nbPlaylist:game.playlists.size,nbTables:game.tables.size,nbCards:game.cards.size,optionsData:s,foundryVersion:`${game.release.generation}.${game.release.build}`};this.sendJsonPostRequest("https://www.uberwald.me/fvtt_appcount/count_post.php",a)}}}
|
||||||
|
|
||||||
|
Hooks.once("init", function () {
|
||||||
|
console.info("Cthulhu Eternal RPG | Initializing System")
|
||||||
|
console.info(SYSTEM.ASCII)
|
||||||
|
|
||||||
|
globalThis.CthulhuEternal = game.system
|
||||||
|
game.system.CONST = SYSTEM
|
||||||
|
|
||||||
|
// Expose the system API
|
||||||
|
game.system.api = {
|
||||||
|
applications,
|
||||||
|
models,
|
||||||
|
documents,
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG.Actor.documentClass = documents.CthulhuEternalActor
|
||||||
|
CONFIG.Actor.dataModels = {
|
||||||
|
character: models.CthulhuEternalProtagonist
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG.Item.documentClass = documents.CthulhuEternalItem
|
||||||
|
CONFIG.Item.dataModels = {
|
||||||
|
skill: models.CthulhuEternalSkill,
|
||||||
|
injury: models.CthulhuEternalInjury,
|
||||||
|
weapon: models.CthulhuEternalWeapon,
|
||||||
|
armor: models.CthulhuEternalArmor,
|
||||||
|
motivation: models.CthulhuEternalMotivation,
|
||||||
|
mentaldisorder: models.CthulhuEternalMentalDisorder,
|
||||||
|
bond: models.CthulhuEternalBond,
|
||||||
|
arcane: models.CthulhuEternalArcane,
|
||||||
|
gear: models.CthulhuEternalGear
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register sheet application classes
|
||||||
|
Actors.unregisterSheet("core", ActorSheet)
|
||||||
|
Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalProtagonistSheet, { types: ["protagonist"], makeDefault: true })
|
||||||
|
|
||||||
|
Items.unregisterSheet("core", ItemSheet)
|
||||||
|
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalSkillSheet, { types: ["skill"], makeDefault: true })
|
||||||
|
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalInjurySheet, { types: ["injury"], makeDefault: true })
|
||||||
|
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalMotivationSheet, { types: ["motivation"], makeDefault: true })
|
||||||
|
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalMentalDisorderSheet, { types: ["mentaldisorder"], makeDefault: true })
|
||||||
|
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalWeaponSheet, { types: ["weapon"], makeDefault: true })
|
||||||
|
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalArcaneSheet, { types: ["arcane"], makeDefault: true })
|
||||||
|
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalArmorSheet, { types: ["armor"], makeDefault: true })
|
||||||
|
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalBondSheet, { types: ["bond"], makeDefault: true })
|
||||||
|
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalGearSheet, { types: ["gear"], makeDefault: true })
|
||||||
|
|
||||||
|
// Other Document Configuration
|
||||||
|
CONFIG.ChatMessage.documentClass = documents.CthulhuEternalChatMessage
|
||||||
|
|
||||||
|
// Dice system configuration
|
||||||
|
CONFIG.Dice.rolls.push(documents.CthulhuEternalRoll)
|
||||||
|
|
||||||
|
game.settings.register("fvtt-cthulhu-eternal", "worldKey", {
|
||||||
|
name: "Unique world key",
|
||||||
|
scope: "world",
|
||||||
|
config: false,
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Activate socket handler
|
||||||
|
game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent)
|
||||||
|
|
||||||
|
|
||||||
|
initControlButtons()
|
||||||
|
|
||||||
|
setupTextEnrichers()
|
||||||
|
|
||||||
|
// Gestion des jets de dés depuis les journaux
|
||||||
|
document.addEventListener("click", (event) => {
|
||||||
|
const anchor = event.target.closest("a.ask-roll-journal")
|
||||||
|
if (!anchor) return
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
const type = anchor.dataset.rollType
|
||||||
|
const target = anchor.dataset.rollTarget
|
||||||
|
const title = anchor.dataset.rollTitle
|
||||||
|
const avantage = anchor.dataset.rollAvantage
|
||||||
|
applications.CthulhuEternalManager.askRollForAll(type, target, title, avantage)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.info("CTHULHU ETERNAL | System Initialized")
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform one-time configuration of system configuration objects.
|
||||||
|
*/
|
||||||
|
function preLocalizeConfig() {
|
||||||
|
const localizeConfigObject = (obj, keys) => {
|
||||||
|
for (let o of Object.values(obj)) {
|
||||||
|
for (let k of keys) {
|
||||||
|
o[k] = game.i18n.localize(o[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONFIG.Dice.rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
||||||
|
|
||||||
|
// localizeConfigObject(SYSTEM.ACTION.TAG_CATEGORIES, ["label"])
|
||||||
|
// localizeConfigObject(CONFIG.Dice.rollModes, ["label"])
|
||||||
|
}
|
||||||
|
|
||||||
|
Hooks.once("ready", function () {
|
||||||
|
console.info("CTHULHU ETERNAL | Ready")
|
||||||
|
game.system.applicationManager = new applications.CthulhuEternalManager()
|
||||||
|
if (game.user.isGM) {
|
||||||
|
//game.system.applicationManager.render(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SYSTEM.DEV_MODE) {
|
||||||
|
registerWorldCount("fvtt-cthulhu-eternal")
|
||||||
|
}
|
||||||
|
_showUserGuide()
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async function _showUserGuide() {
|
||||||
|
if (game.user.isGM) {
|
||||||
|
const newVer = game.system.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Hooks.on("renderChatMessage", (message, html, data) => {
|
||||||
|
const typeMessage = data.message.flags.CthulhuEternal?.typeMessage
|
||||||
|
// Message de demande de jet de dés
|
||||||
|
if (typeMessage === "askRoll") {
|
||||||
|
// Affichage des boutons de jet de dés uniquement pour les joueurs
|
||||||
|
if (game.user.isGM) {
|
||||||
|
html.find(".ask-roll-dice").each((i, btn) => {
|
||||||
|
btn.style.display = "none"
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
html.find(".ask-roll-dice").click((event) => {
|
||||||
|
const btn = $(event.currentTarget)
|
||||||
|
const type = btn.data("type")
|
||||||
|
const value = btn.data("value")
|
||||||
|
const avantage = btn.data("avantage") ?? "="
|
||||||
|
const character = game.user.character
|
||||||
|
if (type === SYSTEM.ROLL_TYPE.RESOURCE) character.rollResource(value)
|
||||||
|
else if (type === SYSTEM.ROLL_TYPE.SAVE) character.rollSave(value, avantage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Hooks.on("updateSetting", async (setting, update, options, id) => {
|
||||||
|
})
|
||||||
|
|
||||||
|
// Dice-so-nice Ready
|
||||||
|
Hooks.once("diceSoNiceReady", (dice3d) => {
|
||||||
|
configureDiceSoNice(dice3d)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a macro when dropping an entity on the hotbar
|
||||||
|
* Item - open roll dialog
|
||||||
|
* Actor - open actor sheet
|
||||||
|
* Journal - open journal sheet
|
||||||
|
*/
|
||||||
|
Hooks.on("hotbarDrop", (bar, data, slot) => {
|
||||||
|
if (["Actor", "Item", "JournalEntry", "roll", "rollDamage", "rollAttack"].includes(data.type)) {
|
||||||
|
Macros.createCthulhuEternalMacro(data, slot);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register world usage statistics
|
||||||
|
* @param {string} registerKey
|
||||||
|
*/
|
||||||
|
function registerWorldCount(registerKey) {
|
||||||
|
if (game.user.isGM) {
|
||||||
|
ClassCounter.registerUsageCount(game.system.id, {})
|
||||||
|
}
|
||||||
|
}
|
219
eslint.config.mjs
Normal file
219
eslint.config.mjs
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
import jsdoc from 'eslint-plugin-jsdoc';
|
||||||
|
import prettier from 'eslint-plugin-prettier';
|
||||||
|
import configPrettier from 'eslint-config-prettier';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
ignores: [
|
||||||
|
"node_modules/",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
"build.mjs",
|
||||||
|
"gulpfile.js"
|
||||||
|
],
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
browser: true,
|
||||||
|
es2022: true,
|
||||||
|
node: true,
|
||||||
|
jquery: true,
|
||||||
|
},
|
||||||
|
ecmaVersion: 2022,
|
||||||
|
sourceType: 'module',
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
jsdoc,
|
||||||
|
prettier
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'array-bracket-spacing': ['warn', 'never'],
|
||||||
|
'array-callback-return': 'warn',
|
||||||
|
'arrow-spacing': 'warn',
|
||||||
|
'comma-dangle': ['warn', 'never'],
|
||||||
|
'comma-style': 'warn',
|
||||||
|
'computed-property-spacing': 'warn',
|
||||||
|
'constructor-super': 'error',
|
||||||
|
'default-param-last': 'warn',
|
||||||
|
'dot-location': ['warn', 'property'],
|
||||||
|
'eol-last': ['error', 'always'],
|
||||||
|
'eqeqeq': ['warn', 'smart'],
|
||||||
|
'func-call-spacing': 'warn',
|
||||||
|
'func-names': ['warn', 'never'],
|
||||||
|
'getter-return': 'warn',
|
||||||
|
'lines-between-class-members': 'warn',
|
||||||
|
'new-parens': ['warn', 'always'],
|
||||||
|
'no-alert': 'warn',
|
||||||
|
'no-array-constructor': 'warn',
|
||||||
|
'no-class-assign': 'warn',
|
||||||
|
'no-compare-neg-zero': 'warn',
|
||||||
|
'no-cond-assign': 'warn',
|
||||||
|
'no-const-assign': 'error',
|
||||||
|
'no-constant-condition': 'warn',
|
||||||
|
'no-constructor-return': 'warn',
|
||||||
|
'no-delete-var': 'warn',
|
||||||
|
'no-dupe-args': 'warn',
|
||||||
|
'no-dupe-class-members': 'warn',
|
||||||
|
'no-dupe-keys': 'warn',
|
||||||
|
'no-duplicate-case': 'warn',
|
||||||
|
'no-duplicate-imports': ['warn', { includeExports: true }],
|
||||||
|
'no-empty': ['warn', { allowEmptyCatch: true }],
|
||||||
|
'no-empty-character-class': 'warn',
|
||||||
|
'no-empty-pattern': 'warn',
|
||||||
|
'no-func-assign': 'warn',
|
||||||
|
'no-global-assign': 'warn',
|
||||||
|
'no-implicit-coercion': ['warn', { allow: ['!!'] }],
|
||||||
|
'no-implied-eval': 'warn',
|
||||||
|
'no-import-assign': 'warn',
|
||||||
|
'no-invalid-regexp': 'warn',
|
||||||
|
'no-irregular-whitespace': 'warn',
|
||||||
|
'no-iterator': 'warn',
|
||||||
|
'no-lone-blocks': 'warn',
|
||||||
|
'no-lonely-if': 'off',
|
||||||
|
'no-loop-func': 'warn',
|
||||||
|
'no-misleading-character-class': 'warn',
|
||||||
|
'no-mixed-operators': 'warn',
|
||||||
|
'no-multi-str': 'warn',
|
||||||
|
'no-multiple-empty-lines': 'warn',
|
||||||
|
'no-new-func': 'warn',
|
||||||
|
'no-new-object': 'warn',
|
||||||
|
'no-new-symbol': 'warn',
|
||||||
|
'no-new-wrappers': 'warn',
|
||||||
|
'no-nonoctal-decimal-escape': 'warn',
|
||||||
|
'no-obj-calls': 'warn',
|
||||||
|
'no-octal': 'warn',
|
||||||
|
'no-octal-escape': 'warn',
|
||||||
|
'no-promise-executor-return': 'warn',
|
||||||
|
'no-proto': 'warn',
|
||||||
|
'no-regex-spaces': 'warn',
|
||||||
|
'no-script-url': 'warn',
|
||||||
|
'no-self-assign': 'warn',
|
||||||
|
'no-self-compare': 'warn',
|
||||||
|
'no-setter-return': 'warn',
|
||||||
|
'no-sequences': 'warn',
|
||||||
|
'no-template-curly-in-string': 'warn',
|
||||||
|
'no-this-before-super': 'error',
|
||||||
|
'no-unexpected-multiline': 'warn',
|
||||||
|
'no-unmodified-loop-condition': 'warn',
|
||||||
|
'no-unneeded-ternary': 'warn',
|
||||||
|
'no-unreachable': 'warn',
|
||||||
|
'no-unreachable-loop': 'warn',
|
||||||
|
'no-unsafe-negation': ['warn', { enforceForOrderingRelations: true }],
|
||||||
|
'no-unsafe-optional-chaining': ['warn', { disallowArithmeticOperators: true }],
|
||||||
|
'no-unused-expressions': 'warn',
|
||||||
|
'no-useless-backreference': 'warn',
|
||||||
|
'no-useless-call': 'warn',
|
||||||
|
'no-useless-catch': 'warn',
|
||||||
|
'no-useless-computed-key': ['warn', { enforceForClassMembers: true }],
|
||||||
|
'no-useless-concat': 'warn',
|
||||||
|
'no-useless-constructor': 'warn',
|
||||||
|
'no-useless-rename': 'warn',
|
||||||
|
'no-useless-return': 'warn',
|
||||||
|
'no-var': 'warn',
|
||||||
|
'no-void': 'warn',
|
||||||
|
'no-whitespace-before-property': 'warn',
|
||||||
|
'prefer-numeric-literals': 'warn',
|
||||||
|
'prefer-object-spread': 'warn',
|
||||||
|
'prefer-regex-literals': 'warn',
|
||||||
|
'prefer-spread': 'warn',
|
||||||
|
'rest-spread-spacing': ['warn', 'never'],
|
||||||
|
'semi-spacing': 'warn',
|
||||||
|
'semi-style': ['warn', 'last'],
|
||||||
|
'space-unary-ops': ['warn', { words: true, nonwords: false }],
|
||||||
|
'switch-colon-spacing': 'warn',
|
||||||
|
'symbol-description': 'warn',
|
||||||
|
'template-curly-spacing': ['warn', 'never'],
|
||||||
|
'unicode-bom': ['warn', 'never'],
|
||||||
|
'use-isnan': ['warn', { enforceForSwitchCase: true, enforceForIndexOf: true }],
|
||||||
|
'valid-typeof': ['warn', { requireStringLiterals: true }],
|
||||||
|
'wrap-iife': ['warn', 'inside'],
|
||||||
|
'arrow-parens': ['warn', 'as-needed', { requireForBlockBody: false }],
|
||||||
|
'capitalized-comments': ['warn', 'always', {
|
||||||
|
ignoreConsecutiveComments: true,
|
||||||
|
ignorePattern: 'noinspection',
|
||||||
|
}],
|
||||||
|
'comma-spacing': 'warn',
|
||||||
|
'dot-notation': 'warn',
|
||||||
|
indent: ['warn', 2, { SwitchCase: 1 }],
|
||||||
|
'key-spacing': 'warn',
|
||||||
|
'keyword-spacing': ['warn', { overrides: { catch: { before: true, after: false } } }],
|
||||||
|
'max-len': ['warn', {
|
||||||
|
code: 180,
|
||||||
|
ignoreTrailingComments: true,
|
||||||
|
ignoreUrls: true,
|
||||||
|
ignoreStrings: true,
|
||||||
|
ignoreTemplateLiterals: true,
|
||||||
|
}],
|
||||||
|
'no-extra-boolean-cast': ['warn', { enforceForLogicalOperands: true }],
|
||||||
|
'no-multi-spaces': ['warn', { ignoreEOLComments: true }],
|
||||||
|
'no-tabs': 'warn',
|
||||||
|
'no-throw-literal': 'error',
|
||||||
|
'no-trailing-spaces': 'warn',
|
||||||
|
'no-useless-escape': 'warn',
|
||||||
|
'nonblock-statement-body-position': ['warn', 'beside'],
|
||||||
|
'one-var': ['warn', 'never'],
|
||||||
|
'operator-linebreak': ['warn', 'before', {
|
||||||
|
overrides: { '=': 'after', '+=': 'after', '-=': 'after' },
|
||||||
|
}],
|
||||||
|
'prefer-template': 'warn',
|
||||||
|
'quote-props': ['warn', 'as-needed', { keywords: false }],
|
||||||
|
quotes: ['warn', 'double', { avoidEscape: true, allowTemplateLiterals: false }],
|
||||||
|
semi: ["error", "never"],
|
||||||
|
'spaced-comment': 'warn',
|
||||||
|
'jsdoc/check-access': 'warn',
|
||||||
|
'jsdoc/check-alignment': 'warn',
|
||||||
|
'jsdoc/check-examples': 'off',
|
||||||
|
'jsdoc/check-indentation': 'off',
|
||||||
|
'jsdoc/check-line-alignment': 'off',
|
||||||
|
'jsdoc/check-param-names': 'warn',
|
||||||
|
'jsdoc/check-property-names': 'warn',
|
||||||
|
'jsdoc/check-syntax': 'off',
|
||||||
|
'jsdoc/check-tag-names': ['warn', { definedTags: ['category'] }],
|
||||||
|
'jsdoc/check-types': 'warn',
|
||||||
|
'jsdoc/check-values': 'warn',
|
||||||
|
'jsdoc/empty-tags': 'warn',
|
||||||
|
'jsdoc/implements-on-classes': 'warn',
|
||||||
|
'jsdoc/match-description': 'off',
|
||||||
|
'jsdoc/newline-after-description': 'off',
|
||||||
|
'jsdoc/no-bad-blocks': 'warn',
|
||||||
|
'jsdoc/no-defaults': 'off',
|
||||||
|
'jsdoc/no-types': 'off',
|
||||||
|
'jsdoc/no-undefined-types': 'off',
|
||||||
|
'jsdoc/require-description': 'warn',
|
||||||
|
'jsdoc/require-description-complete-sentence': 'off',
|
||||||
|
'jsdoc/require-example': 'off',
|
||||||
|
'jsdoc/require-file-overview': 'off',
|
||||||
|
'jsdoc/require-hyphen-before-param-description': ['warn', 'never'],
|
||||||
|
'jsdoc/require-jsdoc': 'warn',
|
||||||
|
'jsdoc/require-param': 'warn',
|
||||||
|
'jsdoc/require-param-description': 'off',
|
||||||
|
'jsdoc/require-param-name': 'warn',
|
||||||
|
'jsdoc/require-param-type': 'warn',
|
||||||
|
'jsdoc/require-property': 'warn',
|
||||||
|
'jsdoc/require-property-description': 'off',
|
||||||
|
'jsdoc/require-property-name': 'warn',
|
||||||
|
'jsdoc/require-property-type': 'warn',
|
||||||
|
'jsdoc/require-returns': 'off',
|
||||||
|
'jsdoc/require-returns-check': 'warn',
|
||||||
|
'jsdoc/require-returns-description': 'off',
|
||||||
|
'jsdoc/require-returns-type': 'warn',
|
||||||
|
'jsdoc/require-throws': 'off',
|
||||||
|
'jsdoc/require-yields': 'warn',
|
||||||
|
'jsdoc/require-yields-check': 'warn',
|
||||||
|
'jsdoc/valid-types': 'off',
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
jsdoc: {
|
||||||
|
preferredTypes: {
|
||||||
|
'.<>': '<>',
|
||||||
|
object: 'Object',
|
||||||
|
Object: 'object',
|
||||||
|
},
|
||||||
|
mode: 'typescript',
|
||||||
|
tagNamePreference: {
|
||||||
|
augments: 'extends',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Ajout de la configuration Prettier qui désactive les règles ESLint en conflit avec Prettier
|
||||||
|
configPrettier
|
||||||
|
];
|
BIN
fonts/caslonpro-bold.otf
Normal file
BIN
fonts/caslonpro-bold.otf
Normal file
Binary file not shown.
BIN
fonts/caslonpro-bolditalic.otf
Normal file
BIN
fonts/caslonpro-bolditalic.otf
Normal file
Binary file not shown.
BIN
fonts/caslonpro-italic.otf
Normal file
BIN
fonts/caslonpro-italic.otf
Normal file
Binary file not shown.
BIN
fonts/caslonpro-regular.otf
Normal file
BIN
fonts/caslonpro-regular.otf
Normal file
Binary file not shown.
BIN
fonts/catfranken-deutsch.ttf
Normal file
BIN
fonts/catfranken-deutsch.ttf
Normal file
Binary file not shown.
31
gulpfile.js
Normal file
31
gulpfile.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
const less = require('gulp-less');
|
||||||
|
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
/* Compile LESS
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
function compileLESS() {
|
||||||
|
return gulp.src("styles/fvtt-cthulhu-eternal.less")
|
||||||
|
.pipe(less())
|
||||||
|
.pipe(gulp.dest("./css"))
|
||||||
|
}
|
||||||
|
const css = gulp.series(compileLESS);
|
||||||
|
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
/* Watch Updates
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
const SIMPLE_LESS = ["styles/*.less"];
|
||||||
|
|
||||||
|
function watchUpdates() {
|
||||||
|
gulp.watch(SIMPLE_LESS, css);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
/* Export Tasks
|
||||||
|
/* ----------------------------------------- */
|
||||||
|
|
||||||
|
exports.default = gulp.series(
|
||||||
|
gulp.parallel(css),
|
||||||
|
watchUpdates
|
||||||
|
);
|
||||||
|
exports.css = css;
|
456
lang/en.json
Normal file
456
lang/en.json
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
{
|
||||||
|
"TYPES": {
|
||||||
|
"Actor": {
|
||||||
|
"protagonist": "Protagonist"
|
||||||
|
},
|
||||||
|
"Item": {
|
||||||
|
"skill": "Skill",
|
||||||
|
"weapon": "Weapon",
|
||||||
|
"armor": "Armor",
|
||||||
|
"injuty": "Spell",
|
||||||
|
"gift": "Gift",
|
||||||
|
"vulnerability": "Vulnerability",
|
||||||
|
"save": "Save",
|
||||||
|
"equipment": "Equipment" ,
|
||||||
|
"shield": "Shield"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"CTHULHUETERNAL": {
|
||||||
|
"Settings": {
|
||||||
|
"Common": "Common",
|
||||||
|
"Classical": "Classical",
|
||||||
|
"Medieval": "Medieval",
|
||||||
|
"Revolution": "Revolution",
|
||||||
|
"Modern": "Modern",
|
||||||
|
"Future": "Future",
|
||||||
|
"Jazz": "Jazz",
|
||||||
|
"WW1": "World War 1",
|
||||||
|
"WW2": "World War 2",
|
||||||
|
"ColdWar": "Cold War",
|
||||||
|
"Victorian": "Victorian"
|
||||||
|
},
|
||||||
|
"Protagonist": {
|
||||||
|
"FIELDS": {
|
||||||
|
"str": {
|
||||||
|
"label": "Strength"
|
||||||
|
},
|
||||||
|
"dex": {
|
||||||
|
"label": "Dexterity"
|
||||||
|
},
|
||||||
|
"int": {
|
||||||
|
"label": "Intelligence"
|
||||||
|
},
|
||||||
|
"wis": {
|
||||||
|
"label": "Wisdom"
|
||||||
|
},
|
||||||
|
"con": {
|
||||||
|
"label": "Constitution"
|
||||||
|
},
|
||||||
|
"char": {
|
||||||
|
"label": "Charisma"
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"label": "Appearance"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Skill": {
|
||||||
|
"Category": {
|
||||||
|
"layperson": "Layperson",
|
||||||
|
"professional": "Professional",
|
||||||
|
"weapon": "Weapon",
|
||||||
|
"armor": "Armor",
|
||||||
|
"resist": "Resist"
|
||||||
|
},
|
||||||
|
"FIELDS": {
|
||||||
|
"diceEvolved": {
|
||||||
|
"label": "Can increase on failure"
|
||||||
|
},
|
||||||
|
"bonus" :{
|
||||||
|
"label": "Bonus"
|
||||||
|
},
|
||||||
|
"base": {
|
||||||
|
"label": "Base"
|
||||||
|
},
|
||||||
|
"rollFailed": {
|
||||||
|
"label": "Roll Failed"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"label": "Description"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Gear": {
|
||||||
|
"FIELDS": {
|
||||||
|
"cost": {
|
||||||
|
"label": "Cost"
|
||||||
|
},
|
||||||
|
"money": {
|
||||||
|
"label": "Money unit"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"label": "Description"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Injury": {
|
||||||
|
"FIELDS": {
|
||||||
|
"cost": {
|
||||||
|
"label": "Cost"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"label": "Description"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Weapon": {
|
||||||
|
"WeaponType": {
|
||||||
|
"melee": "Melee",
|
||||||
|
"ranged": "Ranged"
|
||||||
|
},
|
||||||
|
"FIELDS": {
|
||||||
|
"weaponType": {
|
||||||
|
"label": "Type"
|
||||||
|
},
|
||||||
|
"damageType": {
|
||||||
|
"typeP": {
|
||||||
|
"label": "Piercing"
|
||||||
|
},
|
||||||
|
"typeB": {
|
||||||
|
"label": "Bashing"
|
||||||
|
},
|
||||||
|
"typeS": {
|
||||||
|
"label": "Slashing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"damage": {
|
||||||
|
"damageS": {
|
||||||
|
"label": "Small"
|
||||||
|
},
|
||||||
|
"damageM": {
|
||||||
|
"label": "Medium"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hands": {
|
||||||
|
"label": "Hands"
|
||||||
|
},
|
||||||
|
"defenseMax": {
|
||||||
|
"label": "Defense max"
|
||||||
|
},
|
||||||
|
"secondsToAttack": {
|
||||||
|
"label": "Seconds to attack"
|
||||||
|
},
|
||||||
|
"speed": {
|
||||||
|
"simpleAim": {
|
||||||
|
"label": "Simple aim"
|
||||||
|
},
|
||||||
|
"carefulAim": {
|
||||||
|
"label": "Careful aim"
|
||||||
|
},
|
||||||
|
"focusedAim": {
|
||||||
|
"label": "Focused aim"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defense": {
|
||||||
|
"label": "Defense"
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"pointBlank": {
|
||||||
|
"label": "Point blank"
|
||||||
|
},
|
||||||
|
"short": {
|
||||||
|
"label": "Short"
|
||||||
|
},
|
||||||
|
"medium": {
|
||||||
|
"label": "Medium"
|
||||||
|
},
|
||||||
|
"long": {
|
||||||
|
"label": "Long"
|
||||||
|
},
|
||||||
|
"extreme": {
|
||||||
|
"label": "Extreme"
|
||||||
|
},
|
||||||
|
"outOfSkill": {
|
||||||
|
"label": "Out of skill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"load": {
|
||||||
|
"label": "Load"
|
||||||
|
},
|
||||||
|
"cost": {
|
||||||
|
"label": "Cost"
|
||||||
|
},
|
||||||
|
"money": {
|
||||||
|
"label": "Money unit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Armor": {
|
||||||
|
"Category": {
|
||||||
|
"light": "Light",
|
||||||
|
"medium": "Medium",
|
||||||
|
"heavy": "Heavy"
|
||||||
|
},
|
||||||
|
"FIELDS": {
|
||||||
|
"armortype": {
|
||||||
|
"label": "Category"
|
||||||
|
},
|
||||||
|
"defense": {
|
||||||
|
"label": "Defense"
|
||||||
|
},
|
||||||
|
"movementreduction": {
|
||||||
|
"label": "Movement reduction"
|
||||||
|
},
|
||||||
|
"hp": {
|
||||||
|
"label": "HP"
|
||||||
|
},
|
||||||
|
"damagereduction": {
|
||||||
|
"label": "Damage reduction"
|
||||||
|
},
|
||||||
|
"load": {
|
||||||
|
"label": "Load"
|
||||||
|
},
|
||||||
|
"cost": {
|
||||||
|
"label": "Cost"
|
||||||
|
},
|
||||||
|
"money": {
|
||||||
|
"label": "Money unit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Motivation": {
|
||||||
|
"FIELDS": {
|
||||||
|
"defense": {
|
||||||
|
"label": "Defense"
|
||||||
|
},
|
||||||
|
"movementreduction": {
|
||||||
|
"label": "Movement reduction"
|
||||||
|
},
|
||||||
|
"hp": {
|
||||||
|
"label": "HP"
|
||||||
|
},
|
||||||
|
"standing": {
|
||||||
|
"min":{
|
||||||
|
"label": "Min"
|
||||||
|
},
|
||||||
|
"max":{
|
||||||
|
"label": "Max"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"crouching": {
|
||||||
|
"min":{
|
||||||
|
"label": "Min"
|
||||||
|
},
|
||||||
|
"max":{
|
||||||
|
"label": "Max"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"destruction": {
|
||||||
|
"bashing": {
|
||||||
|
"label": "Bashing"
|
||||||
|
},
|
||||||
|
"slashing": {
|
||||||
|
"label": "Slashing"
|
||||||
|
},
|
||||||
|
"piercing": {
|
||||||
|
"label": "Piercing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autodestruction": {
|
||||||
|
"bashing": {
|
||||||
|
"label": "Bashing"
|
||||||
|
},
|
||||||
|
"slashing": {
|
||||||
|
"label": "Slashing"
|
||||||
|
},
|
||||||
|
"piercing": {
|
||||||
|
"label": "Piercing"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"damagereduction": {
|
||||||
|
"label": "Damage reduction"
|
||||||
|
},
|
||||||
|
"load": {
|
||||||
|
"label": "Load"
|
||||||
|
},
|
||||||
|
"cost": {
|
||||||
|
"label": "Cost"
|
||||||
|
},
|
||||||
|
"money": {
|
||||||
|
"label": "Money unit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MentalDisorder": {
|
||||||
|
"FIELDS": {
|
||||||
|
"description": {
|
||||||
|
"label": "Description"
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"verbal": {
|
||||||
|
"label": "Verbal"
|
||||||
|
},
|
||||||
|
"somatic": {
|
||||||
|
"label": "Somatic"
|
||||||
|
},
|
||||||
|
"material": {
|
||||||
|
"label": "Material"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"level": {
|
||||||
|
"label": "Level"
|
||||||
|
},
|
||||||
|
"cost" : {
|
||||||
|
"label": "Cost"
|
||||||
|
},
|
||||||
|
"castingTime": {
|
||||||
|
"label": "Casting time"
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"label": "Range"
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"label": "Duration"
|
||||||
|
},
|
||||||
|
"areaAffected": {
|
||||||
|
"label": "Area affected"
|
||||||
|
},
|
||||||
|
"savingThrow": {
|
||||||
|
"label": "Saving throw"
|
||||||
|
},
|
||||||
|
"extraAetherPoints": {
|
||||||
|
"label": "Extra aether points"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Bond": {
|
||||||
|
"FIELDS": {
|
||||||
|
"cost": {
|
||||||
|
"label": "Cost"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"label": "Description"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Arcane": {
|
||||||
|
"FIELDS": {
|
||||||
|
"value": {
|
||||||
|
"label": "Value"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"label": "Description"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Label": {
|
||||||
|
"description": "Description",
|
||||||
|
"total": "Total",
|
||||||
|
"langues": "Langues",
|
||||||
|
"profil": "Profil",
|
||||||
|
"details": "Détails",
|
||||||
|
"talents": "Talents",
|
||||||
|
"progressionPossible": "Progression possible",
|
||||||
|
"equipement": "Equipement",
|
||||||
|
"spells" : "Sortilèges",
|
||||||
|
"level": "Niveau",
|
||||||
|
"degats": "Dégâts",
|
||||||
|
"ressource": "Ressource",
|
||||||
|
"sauvegarde": "Sauvegarde",
|
||||||
|
"newArmor": "Nouvelle armure",
|
||||||
|
"newWeapon": "Nouvelle arme",
|
||||||
|
"armor": "Armure",
|
||||||
|
"malus": "Malus",
|
||||||
|
"jet": "Jet de ",
|
||||||
|
"progress": "Progression",
|
||||||
|
"hasProgressed": "A progressé dans la caractéristique",
|
||||||
|
"noProgress": "N'a pas progressé dans la caractéristique",
|
||||||
|
"experience": "Expérience",
|
||||||
|
"experienceDetail": "Expérience {detail}",
|
||||||
|
"maximum": "Maximum"
|
||||||
|
},
|
||||||
|
"Edit": "Editer",
|
||||||
|
"Delete": "Supprimer",
|
||||||
|
"ToggleSheet": "Changer de mode",
|
||||||
|
"Warning": {
|
||||||
|
"dejaDeuxVoies": "Vous avez déjà choisi deux voies",
|
||||||
|
"dejaVoieMajeure": "Vous avez déjà choisi cette voie comme voie majeure",
|
||||||
|
"voieMajeureAjoutee": "Voie majeure ajoutée",
|
||||||
|
"voieMineureAjoutee": "Voie mineure ajoutée",
|
||||||
|
"voieMajeureSupprimee": "Voie majeure supprimée",
|
||||||
|
"voieMineureSupprimee": "Voie mineure supprimée",
|
||||||
|
"plusDeRessource": "Vous n'avez plus de ressource {ressource}"
|
||||||
|
},
|
||||||
|
"Dialog": {
|
||||||
|
"ajoutVoieMajeure": "Ajouter une voie majeure va automatiquement remplacer les caractéristiques, les ressources, les langues et les biens. Continuer ?",
|
||||||
|
"ajoutVoieMajeureTitre": "Ajout d'une voie majeure",
|
||||||
|
"ajoutVoieMineureTitre": "Ajout d'une voie mineure",
|
||||||
|
"suppressionTalents": "Supprimer cette voie va supprimer les talents associés. Continuer ?",
|
||||||
|
"talentDansVoie": "Ce talent est présent dans la voie {path}. Voulez-vous vraiment le supprimer ?",
|
||||||
|
"titleSave": "Jet de sauvegarde",
|
||||||
|
"titleResource": "Jet de ressource",
|
||||||
|
"titleDamage": "Jet de dégâts",
|
||||||
|
"titleAttack": "Jet d'attaque",
|
||||||
|
"titleStandard": "Jet standard"
|
||||||
|
},
|
||||||
|
"Roll": {
|
||||||
|
"save": "Jet de sauvegarde <br> {save}",
|
||||||
|
"resource": "Jet de ressource <br> {resource}",
|
||||||
|
"damage": "Jet de dégâts <br> {item}",
|
||||||
|
"attack": "Jet d'attaque <br> {item}",
|
||||||
|
"roll": "Lancer",
|
||||||
|
"aide": "Aider",
|
||||||
|
"gene": "Gêner",
|
||||||
|
"adversite": "Adversité",
|
||||||
|
"avantagesDesavantages": "Avantages et désavantages",
|
||||||
|
"normal": "Normal",
|
||||||
|
"avantage": "Avec avantage",
|
||||||
|
"desavantage": "Avec désavantage",
|
||||||
|
"doubleAvantage": "Avec double avantage",
|
||||||
|
"doubleDesavantage": "Avec double désavantage",
|
||||||
|
"visibilite": "Visibilité du lancer",
|
||||||
|
"success": "Réussite",
|
||||||
|
"failure": "Echec",
|
||||||
|
"resourceLost": "Ressource perdue",
|
||||||
|
"displayArmor": "{targetName} a une armure de {targetArmor}. <br>Dégâts réels : {realDamage}"
|
||||||
|
},
|
||||||
|
"Tooltip": {
|
||||||
|
"learnedTalents": "Les talents appris sont en gras",
|
||||||
|
"saveIntroTextTooltip": "Caractéristique : {value} <br> Aide : {aide} <br> Gêne : {gene} <br> Modificateur : {modificateur}",
|
||||||
|
"addAttack": "Ajouter une attaque",
|
||||||
|
"addEquipment": "Ajouter une arme, Shift + Click pour ajouter une armure",
|
||||||
|
"addSpell": "Ajouter un sortilège"
|
||||||
|
},
|
||||||
|
"Setting": {
|
||||||
|
"displayOpponentMalus": "Afficher le malus d'adversité",
|
||||||
|
"displayOpponentMalusHint": "Affiche le malus d'adversité pour les joueurs.",
|
||||||
|
"fortune": "Roue de Fortune",
|
||||||
|
"fortuneHint": "Valeur de la roue de Fortune. Nombre de joueurs + 1 en début de partie."
|
||||||
|
},
|
||||||
|
"Chat": {
|
||||||
|
"askFortune": "{name} veut utiliser un point de Fortune !",
|
||||||
|
"askRollForAll": "Jet de {value}",
|
||||||
|
"askRollForOne": "Jet de {value} pour {name}"
|
||||||
|
},
|
||||||
|
"Fortune": {
|
||||||
|
"title": "Roue de Fortune"
|
||||||
|
},
|
||||||
|
"Manager": {
|
||||||
|
"title": "Gestionnaire de Personnages",
|
||||||
|
"player": "Utilisateur",
|
||||||
|
"character": "Personnage",
|
||||||
|
"rob": "Robustesse",
|
||||||
|
"dex": "Dextérité",
|
||||||
|
"int": "Intelligence",
|
||||||
|
"per": "Perception",
|
||||||
|
"vol": "Volonté",
|
||||||
|
"pv": "Points de Vie",
|
||||||
|
"san": "Santé Mentale",
|
||||||
|
"oeil": "Œil",
|
||||||
|
"verbe": "Verbe",
|
||||||
|
"bourse": "Bourse",
|
||||||
|
"magie": "Magie",
|
||||||
|
"roll": "Faire le jet"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
module/applications/_module.mjs
Normal file
11
module/applications/_module.mjs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export { default as CthulhuEternalProtagonistSheet } from "./sheets/protagonist-sheet.mjs";
|
||||||
|
export { default as CthulhuEternalWeaponSheet } from "./sheets/weapon-sheet.mjs"
|
||||||
|
export { default as CthulhuEternalSkillSheet } from "./sheets/skill-sheet.mjs"
|
||||||
|
export { default as CthulhuEternalBondSheet } from "./sheets/bond-sheet.mjs"
|
||||||
|
export { default as CthulhuEternalArcaneSheet } from "./sheets/arcane-sheet.mjs"
|
||||||
|
export { default as CthulhuEternalInjurySheet } from "./sheets/injury-sheet.mjs"
|
||||||
|
export { default as CthulhuEternalArmorSheet } from "./sheets/armor-sheet.mjs"
|
||||||
|
export { default as CthulhuEternalMentalDisorderSheet } from "./sheets/mentaldisorder-sheet.mjs"
|
||||||
|
export { default as CthulhuEternalGearSheet } from "./sheets/gear-sheet.mjs"
|
||||||
|
export { default as CthulhuEternalMotivationSheet } from "./sheets/motivation-sheet.mjs"
|
||||||
|
export { default as CthulhuEternalManager } from "./manager.mjs"
|
142
module/applications/manager.mjs
Normal file
142
module/applications/manager.mjs
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
|
||||||
|
import { SYSTEM } from "../config/system.mjs"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An application for configuring the permissions which are available to each User role.
|
||||||
|
* @extends ApplicationV2
|
||||||
|
* @mixes HandlebarsApplication
|
||||||
|
* @alias PermissionConfig
|
||||||
|
*/
|
||||||
|
export default class CthulhuEternalManager extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
id: "cthulhueternal-application-manager",
|
||||||
|
tag: "form",
|
||||||
|
window: {
|
||||||
|
contentClasses: ["cthulhueternal-manager"],
|
||||||
|
title: "CTHULHUETERNAL.Manager.title",
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
width: "auto",
|
||||||
|
height: "auto",
|
||||||
|
top: 80,
|
||||||
|
left: 400,
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
closeOnSubmit: true,
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
resourceAll: CthulhuEternalManager.#onResourceAll,
|
||||||
|
resourceOne: CthulhuEternalManager.#onResourceOne,
|
||||||
|
saveAll: CthulhuEternalManager.#onSaveAll,
|
||||||
|
saveOne: CthulhuEternalManager.#onSaveOne,
|
||||||
|
openSheet: CthulhuEternalManager.#onOpenSheet,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/manager.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Rendering */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext(_options = {}) {
|
||||||
|
return {
|
||||||
|
players: game.users.filter((u) => u.hasPlayerOwner && u.active),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onResourceAll(event, target) {
|
||||||
|
const value = event.target.dataset.resource
|
||||||
|
CthulhuEternalManager.askRollForAll("resource", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onSaveAll(event, target) {
|
||||||
|
const value = event.target.dataset.save
|
||||||
|
CthulhuEternalManager.askRollForAll("save", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
static #onResourceOne(event, target) {
|
||||||
|
const value = event.target.dataset.resource
|
||||||
|
const recipient = event.target.parentElement.dataset.userId
|
||||||
|
const name = event.target.parentElement.dataset.characterName
|
||||||
|
CthulhuEternalManager.askRollForOne("resource", value, recipient, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onSaveOne(event, target) {
|
||||||
|
const value = event.target.dataset.save
|
||||||
|
const recipient = event.target.parentElement.dataset.userId
|
||||||
|
const name = event.target.parentElement.dataset.characterName
|
||||||
|
CthulhuEternalManager.askRollForOne("save", value, recipient, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
static #onOpenSheet(event, target) {
|
||||||
|
const characterId = event.target.dataset.characterId
|
||||||
|
game.actors.get(characterId).sheet.render(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async askRollForAll(type, value, title = null, avantage = null) {
|
||||||
|
let label = game.i18n.localize(`CTHULHUETERNAL.Manager.${value}`)
|
||||||
|
let text = game.i18n.format("CTHULHUETERNAL.Chat.askRollForAll", { value: label })
|
||||||
|
|
||||||
|
if (avantage) {
|
||||||
|
switch (avantage) {
|
||||||
|
case "++":
|
||||||
|
text += ` ${game.i18n.localize("CTHULHUETERNAL.Roll.doubleAvantage")}`
|
||||||
|
break
|
||||||
|
case "+":
|
||||||
|
text += ` ${game.i18n.localize("CTHULHUETERNAL.Roll.avantage")}`
|
||||||
|
break
|
||||||
|
case "-":
|
||||||
|
text += ` ${game.i18n.localize("CTHULHUETERNAL.Roll.desavantage")}`
|
||||||
|
break
|
||||||
|
case "--":
|
||||||
|
text += ` ${game.i18n.localize("CTHULHUETERNAL.Roll.doubleDesavantage")}`
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatMessage.create({
|
||||||
|
user: game.user.id,
|
||||||
|
content: await renderTemplate(`systems/fvtt-cthulhu-eternal/templates/chat-ask-roll.hbs`, {
|
||||||
|
title: title !== null ? title : "",
|
||||||
|
text: text,
|
||||||
|
rollType: type,
|
||||||
|
value: value,
|
||||||
|
avantage: avantage,
|
||||||
|
}),
|
||||||
|
flags: { tenebris: { typeMessage: "askRoll" } },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static async askRollForOne(type, value, recipient, name) {
|
||||||
|
let label = game.i18n.localize(`CTHULHUETERNAL.Manager.${value}`)
|
||||||
|
const text = game.i18n.format("CTHULHUETERNAL.Chat.askRollForOne", { value: label, name: name })
|
||||||
|
|
||||||
|
game.socket.emit(`system.${SYSTEM.id}`, {
|
||||||
|
action: "askRoll",
|
||||||
|
data: {
|
||||||
|
userId: recipient,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
ChatMessage.create({
|
||||||
|
user: game.user.id,
|
||||||
|
content: await renderTemplate(`systems/fvtt-cthulhu-eternal/templates/chat-ask-roll.hbs`, {
|
||||||
|
text: text,
|
||||||
|
rollType: type,
|
||||||
|
value: value,
|
||||||
|
}),
|
||||||
|
whisper: [recipient],
|
||||||
|
flags: { tenebris: { typeMessage: "askRoll" } },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
28
module/applications/sheets/arcane-sheet.mjs
Normal file
28
module/applications/sheets/arcane-sheet.mjs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalArcaneSheet extends CthulhuEternalItemSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["arcane"],
|
||||||
|
position: {
|
||||||
|
width: 600,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
contentClasses: ["arcane-content"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/arcane.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
}
|
27
module/applications/sheets/armor-sheet.mjs
Normal file
27
module/applications/sheets/armor-sheet.mjs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalArmorSheet extends CthulhuEternalItemSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["armor"],
|
||||||
|
position: {
|
||||||
|
width: 400,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
contentClasses: ["armor-content"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/armor.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
}
|
292
module/applications/sheets/base-actor-sheet.mjs
Normal file
292
module/applications/sheets/base-actor-sheet.mjs
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||||
|
|
||||||
|
export default class CthulhuEternalActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
||||||
|
/**
|
||||||
|
* Different sheet modes.r
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
|
||||||
|
|
||||||
|
constructor(options = {}) {
|
||||||
|
super(options)
|
||||||
|
this.#dragDrop = this.#createDragDropHandlers()
|
||||||
|
}
|
||||||
|
|
||||||
|
#dragDrop
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["fvtt-cthulhu-eternal", "actor"],
|
||||||
|
position: {
|
||||||
|
width: 1400,
|
||||||
|
height: "auto",
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
submitOnChange: true,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
dragDrop: [{ dragSelector: '[data-drag="true"], .rollable', dropSelector: null }],
|
||||||
|
actions: {
|
||||||
|
editImage: CthulhuEternalActorSheet.#onEditImage,
|
||||||
|
toggleSheet: CthulhuEternalActorSheet.#onToggleSheet,
|
||||||
|
edit: CthulhuEternalActorSheet.#onItemEdit,
|
||||||
|
delete: CthulhuEternalActorSheet.#onItemDelete,
|
||||||
|
createSpell: CthulhuEternalActorSheet.#onCreateSpell,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current sheet mode.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
_sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the sheet currently in 'Play' mode?
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get isPlayMode() {
|
||||||
|
return this._sheetMode === this.constructor.SHEET_MODES.PLAY
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the sheet currently in 'Edit' mode?
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get isEditMode() {
|
||||||
|
return this._sheetMode === this.constructor.SHEET_MODES.EDIT
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = {
|
||||||
|
fields: this.document.schema.fields,
|
||||||
|
systemFields: this.document.system.schema.fields,
|
||||||
|
actor: this.document,
|
||||||
|
system: this.document.system,
|
||||||
|
source: this.document.toObject(),
|
||||||
|
enrichedDescription: await TextEditor.enrichHTML(this.document.system.description, { async: true }),
|
||||||
|
isEditMode: this.isEditMode,
|
||||||
|
isPlayMode: this.isPlayMode,
|
||||||
|
isEditable: this.isEditable,
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
_onRender(context, options) {
|
||||||
|
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||||
|
// Add listeners to rollable elements
|
||||||
|
const rollables = this.element.querySelectorAll(".rollable")
|
||||||
|
rollables.forEach((d) => d.addEventListener("click", this._onRoll.bind(this)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// #region Drag-and-Drop Workflow
|
||||||
|
/**
|
||||||
|
* Create drag-and-drop workflow handlers for this Application
|
||||||
|
* @returns {DragDrop[]} An array of DragDrop handlers
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
#createDragDropHandlers() {
|
||||||
|
return this.options.dragDrop.map((d) => {
|
||||||
|
d.permissions = {
|
||||||
|
dragstart: this._canDragStart.bind(this),
|
||||||
|
drop: this._canDragDrop.bind(this),
|
||||||
|
}
|
||||||
|
d.callbacks = {
|
||||||
|
dragstart: this._onDragStart.bind(this),
|
||||||
|
dragover: this._onDragOver.bind(this),
|
||||||
|
drop: this._onDrop.bind(this),
|
||||||
|
}
|
||||||
|
return new DragDrop(d)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback actions which occur when a dragged element is dropped on a target.
|
||||||
|
* @param {DragEvent} event The originating DragEvent
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
async _onDrop(event) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define whether a user is able to begin a dragstart workflow for a given drag selector
|
||||||
|
* @param {string} selector The candidate HTML selector for dragging
|
||||||
|
* @returns {boolean} Can the current user drag this selector?
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_canDragStart(selector) {
|
||||||
|
return this.isEditable
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define whether a user is able to conclude a drag-and-drop workflow for a given drop selector
|
||||||
|
* @param {string} selector The candidate HTML selector for the drop target
|
||||||
|
* @returns {boolean} Can the current user drop on this selector?
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_canDragDrop(selector) {
|
||||||
|
return this.isEditable && this.document.isOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback actions which occur at the beginning of a drag start workflow.
|
||||||
|
* @param {DragEvent} event The originating DragEvent
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_onDragStart(event) {
|
||||||
|
if ("link" in event.target.dataset) return
|
||||||
|
|
||||||
|
const el = event.currentTarget.closest('[data-drag="true"]')
|
||||||
|
const dragType = el.dataset.dragType
|
||||||
|
|
||||||
|
let dragData = {}
|
||||||
|
|
||||||
|
let target
|
||||||
|
switch (dragType) {
|
||||||
|
case "save":
|
||||||
|
target = event.currentTarget.querySelector("input")
|
||||||
|
dragData = {
|
||||||
|
actorId: this.document.id,
|
||||||
|
type: "roll",
|
||||||
|
rollType: target.dataset.rollType,
|
||||||
|
rollTarget: target.dataset.rollTarget,
|
||||||
|
value: target.value,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "resource":
|
||||||
|
target = event.currentTarget.querySelector("select")
|
||||||
|
dragData = {
|
||||||
|
actorId: this.document.id,
|
||||||
|
type: "roll",
|
||||||
|
rollType: target.dataset.rollType,
|
||||||
|
rollTarget: target.dataset.rollTarget,
|
||||||
|
value: target.value,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "damage":
|
||||||
|
dragData = {
|
||||||
|
actorId: this.document.id,
|
||||||
|
type: "rollDamage",
|
||||||
|
rollType: el.dataset.dragType,
|
||||||
|
rollTarget: el.dataset.itemId,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "attack":
|
||||||
|
dragData = {
|
||||||
|
actorId: this.document.id,
|
||||||
|
type: "rollAttack",
|
||||||
|
rollValue: el.dataset.rollValue,
|
||||||
|
rollTarget: el.dataset.rollTarget,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
// Handle other cases or do nothing
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the data you need
|
||||||
|
|
||||||
|
if (!dragData) return
|
||||||
|
|
||||||
|
// Set data transfer
|
||||||
|
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback actions which occur when a dragged element is over a drop target.
|
||||||
|
* @param {DragEvent} event The originating DragEvent
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_onDragOver(event) {}
|
||||||
|
|
||||||
|
async _onDropItem(item) {
|
||||||
|
let itemData = item.toObject()
|
||||||
|
await this.document.createEmbeddedDocuments("Item", [itemData], { renderSheet: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Actions
|
||||||
|
/**
|
||||||
|
* Handle toggling between Edit and Play mode.
|
||||||
|
* @param {Event} event The initiating click event.
|
||||||
|
* @param {HTMLElement} target The current target of the event listener.
|
||||||
|
*/
|
||||||
|
static #onToggleSheet(event, target) {
|
||||||
|
const modes = this.constructor.SHEET_MODES
|
||||||
|
this._sheetMode = this.isEditMode ? modes.PLAY : modes.EDIT
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle changing a Document's image.
|
||||||
|
*
|
||||||
|
* @this CthulhuEternalCharacterSheet
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||||
|
* @returns {Promise}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onEditImage(event, target) {
|
||||||
|
const attr = target.dataset.edit
|
||||||
|
const current = foundry.utils.getProperty(this.document, attr)
|
||||||
|
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
|
||||||
|
const fp = new FilePicker({
|
||||||
|
current,
|
||||||
|
type: "image",
|
||||||
|
redirectToRoot: img ? [img] : [],
|
||||||
|
callback: (path) => {
|
||||||
|
this.document.update({ [attr]: path })
|
||||||
|
},
|
||||||
|
top: this.position.top + 40,
|
||||||
|
left: this.position.left + 10,
|
||||||
|
})
|
||||||
|
return fp.browse()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit an existing item within the Actor
|
||||||
|
* Start with the uuid, if it's not found, fallback to the id (as Embedded item in the actor)
|
||||||
|
* @this CthulhuEternalCharacterSheet
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target the capturing HTML element which defined a [data-action]
|
||||||
|
*/
|
||||||
|
static async #onItemEdit(event, target) {
|
||||||
|
const id = target.getAttribute("data-item-id")
|
||||||
|
const uuid = target.getAttribute("data-item-uuid")
|
||||||
|
let item
|
||||||
|
item = await fromUuid(uuid)
|
||||||
|
if (!item) item = this.document.items.get(id)
|
||||||
|
if (!item) return
|
||||||
|
item.sheet.render(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an existing talent within the Actor
|
||||||
|
* Use the uuid to display the talent sheet
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target the capturing HTML element which defined a [data-action]
|
||||||
|
*/
|
||||||
|
static async #onItemDelete(event, target) {
|
||||||
|
const itemUuid = target.getAttribute("data-item-uuid")
|
||||||
|
const talent = await fromUuid(itemUuid)
|
||||||
|
await talent.deleteDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the creation of a new attack item.
|
||||||
|
*
|
||||||
|
* @param {Event} event The event that triggered the creation of the attack.
|
||||||
|
* @param {Object} target The target object where the attack will be created.
|
||||||
|
* @private
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
static #onCreateSpell(event, target) {
|
||||||
|
const item = this.document.createEmbeddedDocuments("Item", [{ name: "Nouveau sortilège", type: "spell" }])
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
}
|
193
module/applications/sheets/base-item-sheet.mjs
Normal file
193
module/applications/sheets/base-item-sheet.mjs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||||
|
|
||||||
|
export default class CthulhuEternalItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||||
|
/**
|
||||||
|
* Different sheet modes.
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
|
||||||
|
|
||||||
|
constructor(options = {}) {
|
||||||
|
super(options)
|
||||||
|
this.#dragDrop = this.#createDragDropHandlers()
|
||||||
|
}
|
||||||
|
|
||||||
|
#dragDrop
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["fvtt-cthulhu-eternal", "item"],
|
||||||
|
position: {
|
||||||
|
width: 600,
|
||||||
|
height: "auto",
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
submitOnChange: true,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
|
||||||
|
actions: {
|
||||||
|
toggleSheet: CthulhuEternalItemSheet.#onToggleSheet,
|
||||||
|
editImage: CthulhuEternalItemSheet.#onEditImage,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current sheet mode.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
_sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the sheet currently in 'Play' mode?
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get isPlayMode() {
|
||||||
|
return this._sheetMode === this.constructor.SHEET_MODES.PLAY
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the sheet currently in 'Edit' mode?
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get isEditMode() {
|
||||||
|
return this._sheetMode === this.constructor.SHEET_MODES.EDIT
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = {
|
||||||
|
fields: this.document.schema.fields,
|
||||||
|
systemFields: this.document.system.schema.fields,
|
||||||
|
item: this.document,
|
||||||
|
system: this.document.system,
|
||||||
|
source: this.document.toObject(),
|
||||||
|
enrichedDescription: await TextEditor.enrichHTML(this.document.system.description, { async: true }),
|
||||||
|
isEditMode: this.isEditMode,
|
||||||
|
isPlayMode: this.isPlayMode,
|
||||||
|
isEditable: this.isEditable,
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
_onRender(context, options) {
|
||||||
|
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||||
|
}
|
||||||
|
|
||||||
|
// #region Drag-and-Drop Workflow
|
||||||
|
/**
|
||||||
|
* Create drag-and-drop workflow handlers for this Application
|
||||||
|
* @returns {DragDrop[]} An array of DragDrop handlers
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
#createDragDropHandlers() {
|
||||||
|
return this.options.dragDrop.map((d) => {
|
||||||
|
d.permissions = {
|
||||||
|
dragstart: this._canDragStart.bind(this),
|
||||||
|
drop: this._canDragDrop.bind(this),
|
||||||
|
}
|
||||||
|
d.callbacks = {
|
||||||
|
dragstart: this._onDragStart.bind(this),
|
||||||
|
dragover: this._onDragOver.bind(this),
|
||||||
|
drop: this._onDrop.bind(this),
|
||||||
|
}
|
||||||
|
return new DragDrop(d)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define whether a user is able to begin a dragstart workflow for a given drag selector
|
||||||
|
* @param {string} selector The candidate HTML selector for dragging
|
||||||
|
* @returns {boolean} Can the current user drag this selector?
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_canDragStart(selector) {
|
||||||
|
return this.isEditable
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define whether a user is able to conclude a drag-and-drop workflow for a given drop selector
|
||||||
|
* @param {string} selector The candidate HTML selector for the drop target
|
||||||
|
* @returns {boolean} Can the current user drop on this selector?
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_canDragDrop(selector) {
|
||||||
|
return this.isEditable && this.document.isOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback actions which occur at the beginning of a drag start workflow.
|
||||||
|
* @param {DragEvent} event The originating DragEvent
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_onDragStart(event) {
|
||||||
|
const el = event.currentTarget
|
||||||
|
if ("link" in event.target.dataset) return
|
||||||
|
|
||||||
|
// Extract the data you need
|
||||||
|
let dragData = null
|
||||||
|
|
||||||
|
if (!dragData) return
|
||||||
|
|
||||||
|
// Set data transfer
|
||||||
|
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback actions which occur when a dragged element is over a drop target.
|
||||||
|
* @param {DragEvent} event The originating DragEvent
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_onDragOver(event) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback actions which occur when a dragged element is dropped on a target.
|
||||||
|
* @param {DragEvent} event The originating DragEvent
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
async _onDrop(event) {}
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Actions
|
||||||
|
/**
|
||||||
|
* Handle toggling between Edit and Play mode.
|
||||||
|
* @param {Event} event The initiating click event.
|
||||||
|
* @param {HTMLElement} target The current target of the event listener.
|
||||||
|
*/
|
||||||
|
static #onToggleSheet(event, target) {
|
||||||
|
const modes = this.constructor.SHEET_MODES
|
||||||
|
this._sheetMode = this.isEditMode ? modes.PLAY : modes.EDIT
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle changing a Document's image.
|
||||||
|
*
|
||||||
|
* @this CthulhuEternalCharacterSheet
|
||||||
|
* @param {PointerEvent} event The originating click event
|
||||||
|
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||||
|
* @returns {Promise}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onEditImage(event, target) {
|
||||||
|
const attr = target.dataset.edit
|
||||||
|
const current = foundry.utils.getProperty(this.document, attr)
|
||||||
|
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
|
||||||
|
const fp = new FilePicker({
|
||||||
|
current,
|
||||||
|
type: "image",
|
||||||
|
redirectToRoot: img ? [img] : [],
|
||||||
|
callback: (path) => {
|
||||||
|
this.document.update({ [attr]: path })
|
||||||
|
},
|
||||||
|
top: this.position.top + 40,
|
||||||
|
left: this.position.left + 10,
|
||||||
|
})
|
||||||
|
return fp.browse()
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
|
}
|
28
module/applications/sheets/bond-sheet.mjs
Normal file
28
module/applications/sheets/bond-sheet.mjs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalGiftSheet extends CthulhuEternalItemSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["bond"],
|
||||||
|
position: {
|
||||||
|
width: 600,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
contentClasses: ["bond-content"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/bond.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
}
|
27
module/applications/sheets/gear-sheet.mjs
Normal file
27
module/applications/sheets/gear-sheet.mjs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalGearSheet extends CthulhuEternalItemSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["gear"],
|
||||||
|
position: {
|
||||||
|
width: 600,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
contentClasses: ["gear-content"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/gear.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
}
|
28
module/applications/sheets/injury-sheet.mjs
Normal file
28
module/applications/sheets/injury-sheet.mjs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalInjurySheet extends CthulhuEternalItemSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["injury"],
|
||||||
|
position: {
|
||||||
|
width: 600,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
contentClasses: ["injury-content"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/injury.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
}
|
21
module/applications/sheets/mentaldisorder-sheet.mjs
Normal file
21
module/applications/sheets/mentaldisorder-sheet.mjs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalMentalDisorderSheet extends CthulhuEternalItemSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["mentaldisorder"],
|
||||||
|
position: {
|
||||||
|
width: 450,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
contentClasses: ["mentaldisorder-content"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/mentaldisorder.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
27
module/applications/sheets/motivation-sheet.mjs
Normal file
27
module/applications/sheets/motivation-sheet.mjs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalMotivationSheet extends CthulhuEternalItemSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["motivation"],
|
||||||
|
position: {
|
||||||
|
width: 620,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
contentClasses: ["motivation-content"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/motivation.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
}
|
173
module/applications/sheets/protagonist-sheet.mjs
Normal file
173
module/applications/sheets/protagonist-sheet.mjs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
import CthulhuEternalActorSheet from "./base-actor-sheet.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["protagonist"],
|
||||||
|
position: {
|
||||||
|
width: 1150,
|
||||||
|
height: 780,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
contentClasses: ["protagonist-content"],
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
createEquipment: CthulhuEternalProtagonistSheet.#onCreateEquipment,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/character-main.hbs",
|
||||||
|
},
|
||||||
|
tabs: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/generic/tab-navigation.hbs",
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/character-items.hbs",
|
||||||
|
},
|
||||||
|
biography: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/character-biography.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
tabGroups = {
|
||||||
|
sheet: "items",
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare an array of form header tabs.
|
||||||
|
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||||
|
*/
|
||||||
|
#getTabs() {
|
||||||
|
const tabs = {
|
||||||
|
items: { id: "items", group: "sheet", icon: "fa-solid fa-shapes", label: "CTHULHUETERNAL.Character.Label.details" },
|
||||||
|
biography: { id: "biography", group: "sheet", icon: "fa-solid fa-book", label: "CTHULHUETERNAL.Character.Label.biography" },
|
||||||
|
}
|
||||||
|
for (const v of Object.values(tabs)) {
|
||||||
|
v.active = this.tabGroups[v.group] === v.id
|
||||||
|
v.cssClass = v.active ? "active" : ""
|
||||||
|
}
|
||||||
|
return tabs
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
context.tabs = this.#getTabs()
|
||||||
|
|
||||||
|
context.tooltipsCaracteristiques = {
|
||||||
|
}
|
||||||
|
|
||||||
|
context.tooltipsRessources = {
|
||||||
|
}
|
||||||
|
|
||||||
|
context.rollType = {
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
_generateTooltip(type, target) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _preparePartContext(partId, context) {
|
||||||
|
const doc = this.document
|
||||||
|
switch (partId) {
|
||||||
|
case "main":
|
||||||
|
context.enrichedBiens = await TextEditor.enrichHTML(doc.system.biens, { async: true })
|
||||||
|
break
|
||||||
|
case "items":
|
||||||
|
context.tab = context.tabs.items
|
||||||
|
context.weapons = doc.itemTypes.weapon
|
||||||
|
context.armors = doc.itemTypes.armor
|
||||||
|
context.spells = doc.itemTypes.spell
|
||||||
|
context.hasSpells = context.spells.length > 0
|
||||||
|
break
|
||||||
|
case "biography":
|
||||||
|
context.tab = context.tabs.biography
|
||||||
|
context.enrichedDescription = await TextEditor.enrichHTML(doc.system.description, { async: true })
|
||||||
|
context.enrichedNotes = await TextEditor.enrichHTML(doc.system.notes, { async: true })
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
// #region Drag-and-Drop Workflow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback actions which occur when a dragged element is dropped on a target.
|
||||||
|
* @param {DragEvent} event The originating DragEvent
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
async _onDrop(event) {
|
||||||
|
if (!this.isEditable || !this.isEditMode) return
|
||||||
|
const data = TextEditor.getDragEventData(event)
|
||||||
|
|
||||||
|
// Handle different data types
|
||||||
|
switch (data.type) {
|
||||||
|
case "Item":
|
||||||
|
const item = await fromUuid(data.uuid)
|
||||||
|
if (!["path", "weapon", "armor", "spell"].includes(item.type)) return
|
||||||
|
if (item.type === "path") return this.#onDropPathItem(item)
|
||||||
|
if (item.type === "weapon") return super._onDropItem(item)
|
||||||
|
if (item.type === "armor") return this._onDropItem(item)
|
||||||
|
if (item.type === "spell") return this._onDropItem(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async #onDropPathItem(item) {
|
||||||
|
await this.document.addPath(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new attack item directly from the sheet and embeds it into the document.
|
||||||
|
* @param {Event} event The initiating click event.
|
||||||
|
* @param {HTMLElement} target The current target of the event listener.
|
||||||
|
*/
|
||||||
|
static #onCreateEquipment(event, target) {
|
||||||
|
// Création d'une armure
|
||||||
|
if (event.shiftKey) {
|
||||||
|
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newArmor"), type: "armor" }])
|
||||||
|
}
|
||||||
|
// Création d'une arme
|
||||||
|
else {
|
||||||
|
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newWeapon"), type: "weapon" }])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the roll action triggered by user interaction.
|
||||||
|
*
|
||||||
|
* @param {PointerEvent} event The event object representing the user interaction.
|
||||||
|
* @param {HTMLElement} target The target element that triggered the roll.
|
||||||
|
*
|
||||||
|
* @returns {Promise<void>} A promise that resolves when the roll action is complete.
|
||||||
|
*
|
||||||
|
* @throws {Error} Throws an error if the roll type is not recognized.
|
||||||
|
*
|
||||||
|
* @description This method checks the current mode (edit or not) and determines the type of roll
|
||||||
|
* (save, resource, or damage) based on the target element's data attributes. It retrieves the
|
||||||
|
* corresponding value from the document's system and performs the roll.
|
||||||
|
*/
|
||||||
|
async _onRoll(event, target) {
|
||||||
|
if (this.isEditMode) return
|
||||||
|
// Jet de sauvegarde
|
||||||
|
let elt = event.currentTarget.querySelector("input")
|
||||||
|
// Jet de ressource
|
||||||
|
if (!elt) elt = event.currentTarget.querySelector("select")
|
||||||
|
// Jet de dégâts
|
||||||
|
if (!elt) elt = event.currentTarget
|
||||||
|
const rollType = elt.dataset.rollType
|
||||||
|
let rollTarget
|
||||||
|
switch (rollType) {
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
await this.document.system.roll(rollType, rollTarget)
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
|
}
|
28
module/applications/sheets/skill-sheet.mjs
Normal file
28
module/applications/sheets/skill-sheet.mjs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalSkillSheet extends CthulhuEternalItemSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["skill"],
|
||||||
|
position: {
|
||||||
|
width: 600,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
contentClasses: ["skill-content"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/skill.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
}
|
21
module/applications/sheets/weapon-sheet.mjs
Normal file
21
module/applications/sheets/weapon-sheet.mjs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import LethalFantasyItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
export default class LethalFantasyWeaponSheet extends LethalFantasyItemSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["weapon"],
|
||||||
|
position: {
|
||||||
|
width: 620,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
contentClasses: ["weapon-content"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-cthulhu-eternal/templates/weapon.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
5
module/config/bond.mjs
Normal file
5
module/config/bond.mjs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const BOND_TYPE = {
|
||||||
|
"individual": "CTHULHUETERNAL.Weapon.WeaponType.melee",
|
||||||
|
"community": "CTHULHUETERNAL.Weapon.WeaponType.ranged"
|
||||||
|
}
|
||||||
|
|
57
module/config/protagonist.mjs
Normal file
57
module/config/protagonist.mjs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
export const CHARACTERISTICS = Object.freeze({
|
||||||
|
str: {
|
||||||
|
id: "str",
|
||||||
|
label: "CTHULHUETERNAL.Character.str.label"
|
||||||
|
},
|
||||||
|
int: {
|
||||||
|
id: "int",
|
||||||
|
label: "CTHULHUETERNAL.Character.int.label"
|
||||||
|
},
|
||||||
|
wis: {
|
||||||
|
id: "wis",
|
||||||
|
label: "CTHULHUETERNAL.Character.wis.label"
|
||||||
|
},
|
||||||
|
dex: {
|
||||||
|
id: "dex",
|
||||||
|
label: "CTHULHUETERNAL.Character.dex.label"
|
||||||
|
},
|
||||||
|
con: {
|
||||||
|
id: "con",
|
||||||
|
label: "CTHULHUETERNAL.Character.con.label"
|
||||||
|
},
|
||||||
|
cha: {
|
||||||
|
id: "cha",
|
||||||
|
label: "CTHULHUETERNAL.Character.cha.label"
|
||||||
|
},
|
||||||
|
app: {
|
||||||
|
id: "app",
|
||||||
|
label: "CTHULHUETERNAL.Character.app.label"
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const SAVES = Object.freeze({
|
||||||
|
str: {
|
||||||
|
id: "str",
|
||||||
|
label: "CTHULHUETERNAL.Character.str.label"
|
||||||
|
},
|
||||||
|
agility: {
|
||||||
|
id: "agility",
|
||||||
|
label: "CTHULHUETERNAL.Character.agility.label"
|
||||||
|
},
|
||||||
|
dying: {
|
||||||
|
id: "dying",
|
||||||
|
label: "CTHULHUETERNAL.Character.dying.label"
|
||||||
|
},
|
||||||
|
will: {
|
||||||
|
id: "will",
|
||||||
|
label: "CTHULHUETERNAL.Character.will.label"
|
||||||
|
},
|
||||||
|
dodge: {
|
||||||
|
id: "dodge",
|
||||||
|
label: "CTHULHUETERNAL.Character.dodge.label"
|
||||||
|
},
|
||||||
|
toughness: {
|
||||||
|
id: "toughness",
|
||||||
|
label: "CTHULHUETERNAL.Character.toughness.label"
|
||||||
|
}
|
||||||
|
})
|
45
module/config/system.mjs
Normal file
45
module/config/system.mjs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import * as PROTAGONIST from "./protagonist.mjs"
|
||||||
|
import * as WEAPON from "./weapon.mjs"
|
||||||
|
import * as BOND from "./bond.mjs"
|
||||||
|
|
||||||
|
|
||||||
|
export const SYSTEM_ID = "fvtt-cthulhu-eternal"
|
||||||
|
|
||||||
|
export const AVAILABLE_SETTINGS = {
|
||||||
|
common: "CTHULHUETERNAL.Settings.Common",
|
||||||
|
modern: "CTHULHUETERNAL.Settings.Modern",
|
||||||
|
jazz: "CTHULHUETERNAL.Settings.Jazz",
|
||||||
|
future: "CTHULHUETERNAL.Settings.Future",
|
||||||
|
coldwar: "CTHULHUETERNAL.Settings.ColdWar",
|
||||||
|
ww2: "CTHULHUETERNAL.Settings.WW2",
|
||||||
|
ww1: "CTHULHUETERNAL.Settings.WW1",
|
||||||
|
victorian: "CTHULHUETERNAL.Settings.Victorian",
|
||||||
|
revolution: "CTHULHUETERNAL.Settings.Revolution",
|
||||||
|
medieval: "CTHULHUETERNAL.Settings.Medieval",
|
||||||
|
classical: "CTHULHUETERNAL.Settings.Classical"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ASCII = `
|
||||||
|
······················································································································
|
||||||
|
: :
|
||||||
|
:@@@ @@@@@@@@ @@@@@@@ @@@ @@@ @@@@@@ @@@ @@@@@@@@ @@@@@@ @@@ @@@ @@@@@@@ @@@@@@ @@@@@@ @@@ @@@ :
|
||||||
|
:@@! @@! @!! @@! @@@ @@! @@@ @@! @@! @@! @@@ @@!@!@@@ @!! @@! @@@ !@@ @@! !@@ :
|
||||||
|
:@!! @!!!:! @!! @!@!@!@! @!@!@!@! @!! @!!!:! @!@!@!@! @!@@!!@! @!! @!@!@!@! !@@!! !@!@! :
|
||||||
|
:!!: !!: !!: !!: !!! !!: !!! !!: !!: !!: !!! !!: !!! !!: !!: !!! !:! !!: :
|
||||||
|
:: ::.: : : :: :: : : : : : : : : ::.: : : : : : :: : : : : : ::.: : .: :
|
||||||
|
: :
|
||||||
|
······················································································································
|
||||||
|
`
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include all constant definitions within the SYSTEM global export
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
export const SYSTEM = {
|
||||||
|
id: SYSTEM_ID,
|
||||||
|
CHARACTERISTICS: PROTAGONIST.CHARACTERISTICS,
|
||||||
|
WEAPON_TYPE: WEAPON.WEAPON_TYPE,
|
||||||
|
BOND_TYPE: BOND.BOND_TYPE,
|
||||||
|
AVAILABLE_SETTINGS,
|
||||||
|
ASCII
|
||||||
|
}
|
9
module/config/weapon.mjs
Normal file
9
module/config/weapon.mjs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export const WEAPON_TYPE = {
|
||||||
|
"melee": "CTHULHUETERNAL.Weapon.WeaponType.melee",
|
||||||
|
"ranged": "CTHULHUETERNAL.Weapon.WeaponType.ranged"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WEAPON_RANGE_UNIT = {
|
||||||
|
"yard": "CTHULHUETERNAL.Weapon.RangeUnit.yard",
|
||||||
|
"meter": "CTHULHUETERNAL.Weapon.RangeUnit.meter"
|
||||||
|
}
|
44
module/control-buttons.mjs
Normal file
44
module/control-buttons.mjs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Menu spécifique au système
|
||||||
|
*/
|
||||||
|
export function initControlButtons() {
|
||||||
|
CONFIG.Canvas.layers.tenebris = { layerClass: ControlsLayer, group: "primary" }
|
||||||
|
|
||||||
|
Hooks.on("getSceneControlButtons", (btns) => {
|
||||||
|
let menu = []
|
||||||
|
|
||||||
|
menu.push({
|
||||||
|
name: "fortune",
|
||||||
|
title: game.i18n.localize("TENEBRIS.Fortune.title"),
|
||||||
|
icon: "fa-solid fa-clover",
|
||||||
|
button: true,
|
||||||
|
onClick: () => {
|
||||||
|
if (!foundry.applications.instances.has("tenebris-application-fortune")) {
|
||||||
|
game.system.applicationFortune.render(true)
|
||||||
|
} else game.system.applicationFortune.close()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (game.user.isGM) {
|
||||||
|
menu.push({
|
||||||
|
name: "gm-manager",
|
||||||
|
title: game.i18n.localize("TENEBRIS.Manager.title"),
|
||||||
|
icon: "fa-solid fa-users",
|
||||||
|
button: true,
|
||||||
|
onClick: () => {
|
||||||
|
if (!foundry.applications.instances.has("tenebris-application-manager")) {
|
||||||
|
game.system.applicationManager.render(true)
|
||||||
|
} else game.system.applicationManager.close()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
btns.push({
|
||||||
|
name: "tenebris",
|
||||||
|
title: "Cthulhu CthulhuEternal",
|
||||||
|
icon: "tenebris",
|
||||||
|
layer: "tenebris",
|
||||||
|
tools: menu,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
4
module/documents/_module.mjs
Normal file
4
module/documents/_module.mjs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export { default as CthulhuEternalActor } from "./actor.mjs"
|
||||||
|
export { default as CthulhuEternalItem } from "./item.mjs"
|
||||||
|
export { default as CthulhuEternalRoll } from "./roll.mjs"
|
||||||
|
export { default as CthulhuEternalChatMessage } from "./chat-message.mjs"
|
17
module/documents/actor.mjs
Normal file
17
module/documents/actor.mjs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export default class CthulhuEternalActor extends Actor {
|
||||||
|
async _preCreate(data, options, user) {
|
||||||
|
await super._preCreate(data, options, user)
|
||||||
|
|
||||||
|
// Configure prototype token settings
|
||||||
|
const prototypeToken = {}
|
||||||
|
if (this.type === "protagonist") {
|
||||||
|
Object.assign(prototypeToken, {
|
||||||
|
sight: { enabled: true },
|
||||||
|
actorLink: true,
|
||||||
|
disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY,
|
||||||
|
})
|
||||||
|
this.updateSource({ prototypeToken })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
21
module/documents/chat-message.mjs
Normal file
21
module/documents/chat-message.mjs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import CthulhuEternalRoll from "./roll.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalChatMessage extends ChatMessage {
|
||||||
|
async _renderRollContent(messageData) {
|
||||||
|
const data = messageData.message
|
||||||
|
if (this.rolls[0] instanceof CthulhuEternalRoll) {
|
||||||
|
const isPrivate = !this.isContentVisible
|
||||||
|
// _renderRollHTML va appeler render sur tous les rolls
|
||||||
|
const rollHTML = await this._renderRollHTML(isPrivate)
|
||||||
|
if (isPrivate) {
|
||||||
|
data.flavor = game.i18n.format("CHAT.PrivateRollContent", { user: this.user.name })
|
||||||
|
messageData.isWhisper = false
|
||||||
|
messageData.alias = this.user.name
|
||||||
|
}
|
||||||
|
data.content = `<section class="dice-rolls">${rollHTML}</section>`
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return super._renderRollContent(messageData)
|
||||||
|
}
|
||||||
|
}
|
1
module/documents/item.mjs
Normal file
1
module/documents/item.mjs
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default class CthulhuEternalItem extends Item {}
|
583
module/documents/roll.mjs
Normal file
583
module/documents/roll.mjs
Normal file
@ -0,0 +1,583 @@
|
|||||||
|
import CthulhuEternalUtils from "../utils.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalRoll extends Roll {
|
||||||
|
/**
|
||||||
|
* The HTML template path used to render dice checks of this type
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
static CHAT_TEMPLATE = "systems/fvtt-cthulhu-eternal/templates/chat-message.hbs"
|
||||||
|
|
||||||
|
get type() {
|
||||||
|
return this.options.type
|
||||||
|
}
|
||||||
|
|
||||||
|
get isDamage() {
|
||||||
|
return this.type === ROLL_TYPE.DAMAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
get target() {
|
||||||
|
return this.options.target
|
||||||
|
}
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
return this.options.value
|
||||||
|
}
|
||||||
|
|
||||||
|
get treshold() {
|
||||||
|
return this.options.treshold
|
||||||
|
}
|
||||||
|
|
||||||
|
get actorId() {
|
||||||
|
return this.options.actorId
|
||||||
|
}
|
||||||
|
|
||||||
|
get actorName() {
|
||||||
|
return this.options.actorName
|
||||||
|
}
|
||||||
|
|
||||||
|
get actorImage() {
|
||||||
|
return this.options.actorImage
|
||||||
|
}
|
||||||
|
|
||||||
|
get introText() {
|
||||||
|
return this.options.introText
|
||||||
|
}
|
||||||
|
|
||||||
|
get introTextTooltip() {
|
||||||
|
return this.options.introTextTooltip
|
||||||
|
}
|
||||||
|
|
||||||
|
get aide() {
|
||||||
|
return this.options.aide
|
||||||
|
}
|
||||||
|
|
||||||
|
get gene() {
|
||||||
|
return this.options.gene
|
||||||
|
}
|
||||||
|
|
||||||
|
get modificateur() {
|
||||||
|
return this.options.modificateur
|
||||||
|
}
|
||||||
|
|
||||||
|
get avantages() {
|
||||||
|
return this.options.avantages
|
||||||
|
}
|
||||||
|
|
||||||
|
get resultType() {
|
||||||
|
return this.options.resultType
|
||||||
|
}
|
||||||
|
|
||||||
|
get isFailure() {
|
||||||
|
return this.resultType === "failure"
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasTarget() {
|
||||||
|
return this.options.hasTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
get targetName() {
|
||||||
|
return this.options.targetName
|
||||||
|
}
|
||||||
|
|
||||||
|
get targetArmor() {
|
||||||
|
return this.options.targetArmor
|
||||||
|
}
|
||||||
|
|
||||||
|
get targetMalus() {
|
||||||
|
return this.options.targetMalus
|
||||||
|
}
|
||||||
|
|
||||||
|
get realDamage() {
|
||||||
|
return this.options.realDamage
|
||||||
|
}
|
||||||
|
|
||||||
|
get rollAdvantage() {
|
||||||
|
return this.options.rollAdvantage
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates introductory text based on the roll type.
|
||||||
|
*
|
||||||
|
* @returns {string} The formatted introductory text for the roll.
|
||||||
|
*/
|
||||||
|
_createIntroText() {
|
||||||
|
let text
|
||||||
|
|
||||||
|
switch (this.type) {
|
||||||
|
case ROLL_TYPE.SAVE:
|
||||||
|
const saveLabel = game.i18n.localize(`TENEBRIS.Character.FIELDS.caracteristiques.${this.target}.valeur.label`)
|
||||||
|
text = game.i18n.format("TENEBRIS.Roll.save", { save: saveLabel })
|
||||||
|
text = text.concat("<br>").concat(`Seuil : ${this.treshold}`)
|
||||||
|
break
|
||||||
|
case ROLL_TYPE.RESOURCE:
|
||||||
|
const resourceLabel = game.i18n.localize(`TENEBRIS.Character.FIELDS.ressources.${this.target}.valeur.label`)
|
||||||
|
text = game.i18n.format("TENEBRIS.Roll.resource", { resource: resourceLabel })
|
||||||
|
break
|
||||||
|
case ROLL_TYPE.DAMAGE:
|
||||||
|
const damageLabel = this.target
|
||||||
|
text = game.i18n.format("TENEBRIS.Roll.damage", { item: damageLabel })
|
||||||
|
break
|
||||||
|
case ROLL_TYPE.ATTACK:
|
||||||
|
const attackLabel = this.target
|
||||||
|
text = game.i18n.format("TENEBRIS.Roll.attack", { item: attackLabel })
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an introductory text tooltip with characteristics and modifiers.
|
||||||
|
*
|
||||||
|
* @returns {string} A formatted string containing the value, help, hindrance, and modifier.
|
||||||
|
*/
|
||||||
|
_createIntroTextTooltip() {
|
||||||
|
let tooltip = game.i18n.format("TENEBRIS.Tooltip.saveIntroTextTooltip", { value: this.value, aide: this.aide, gene: this.gene, modificateur: this.modificateur })
|
||||||
|
if (this.hasTarget) {
|
||||||
|
tooltip = tooltip.concat(`<br>Cible : ${this.targetName}`)
|
||||||
|
}
|
||||||
|
return tooltip
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompt the user with a dialog to configure and execute a roll.
|
||||||
|
*
|
||||||
|
* @param {Object} options Configuration options for the roll.
|
||||||
|
* @param {string} options.rollType The type of roll being performed (e.g., RESOURCE, DAMAGE, ATTACK, SAVE).
|
||||||
|
* @param {string} options.rollValue The initial value or formula for the roll.
|
||||||
|
* @param {string} options.rollTarget The target of the roll.
|
||||||
|
* @param {"="|"+"|"++"|"-"|"--"} options.rollAdvantage If there is an avantage (+), a disadvantage (-), a double advantage (++), a double disadvantage (--) or a normal roll (=).
|
||||||
|
* @param {string} options.actorId The ID of the actor performing the roll.
|
||||||
|
* @param {string} options.actorName The name of the actor performing the roll.
|
||||||
|
* @param {string} options.actorImage The image of the actor performing the roll.
|
||||||
|
* @param {boolean} options.hasTarget Whether the roll has a target.
|
||||||
|
* @param {Object} options.target The target of the roll, if any.
|
||||||
|
* @param {Object} options.data Additional data for the roll.
|
||||||
|
*
|
||||||
|
* @returns {Promise<Object|null>} The roll result or null if the dialog was cancelled.
|
||||||
|
*/
|
||||||
|
static async prompt(options = {}) {
|
||||||
|
let formula = options.rollValue
|
||||||
|
|
||||||
|
// Formula for a resource roll
|
||||||
|
if (options.rollType === ROLL_TYPE.RESOURCE) {
|
||||||
|
let ressource = game.i18n.localize(`TENEBRIS.Character.FIELDS.ressources.${options.rollTarget}.valeur.label`)
|
||||||
|
if (formula === "0" || formula === "") {
|
||||||
|
ui.notifications.warn(game.i18n.format("TENEBRIS.Warning.plusDeRessource", { ressource: ressource }))
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
||||||
|
const fieldRollMode = new foundry.data.fields.StringField({
|
||||||
|
choices: rollModes,
|
||||||
|
blank: false,
|
||||||
|
default: "public",
|
||||||
|
})
|
||||||
|
|
||||||
|
const choiceAide = foundry.utils.mergeObject({ 0: "0" }, options.rollValue <= 10 ? { 1: "1" } : { 1: "1", 2: "2" })
|
||||||
|
const choiceGene = {
|
||||||
|
0: "0",
|
||||||
|
"-1": "-1",
|
||||||
|
"-2": "-2",
|
||||||
|
"-3": "-3",
|
||||||
|
"-4": "-4",
|
||||||
|
"-5": "-5",
|
||||||
|
"-6": "-6",
|
||||||
|
"-7": "-7",
|
||||||
|
"-8": "-8",
|
||||||
|
"-9": "-9",
|
||||||
|
"-10": "-10",
|
||||||
|
}
|
||||||
|
const choiceAvantage = { normal: "Normal", avantage: "Avantage", desavantage: "Désavantage", doubleAvantage: "Double avantage", doubleDesavantage: "Double désavantage" }
|
||||||
|
const choiceModificateur = {
|
||||||
|
0: "0",
|
||||||
|
"-1": "-1",
|
||||||
|
"-2": "-2",
|
||||||
|
"-3": "-3",
|
||||||
|
"-4": "-4",
|
||||||
|
"-5": "-5",
|
||||||
|
"-6": "-6",
|
||||||
|
"-7": "-7",
|
||||||
|
"-8": "-8",
|
||||||
|
"-9": "-9",
|
||||||
|
"-10": "-10",
|
||||||
|
}
|
||||||
|
|
||||||
|
let damageDice
|
||||||
|
let damageDiceMax
|
||||||
|
let damageDiceFinal
|
||||||
|
let damageDiceLowered
|
||||||
|
|
||||||
|
// Damage roll : check the roll is not above the maximum damage
|
||||||
|
if (options.rollType === ROLL_TYPE.DAMAGE) {
|
||||||
|
damageDice = options.rollValue
|
||||||
|
damageDiceMax = game.actors.get(options.actorId).system.dmax.valeur
|
||||||
|
damageDiceFinal = CthulhuEternalUtils.maxDamage(damageDice, damageDiceMax)
|
||||||
|
damageDiceLowered = damageDiceFinal !== damageDice
|
||||||
|
// Récupération du nom de l'objet si c'est un jet depuis la fiche de l'acteur
|
||||||
|
// Si c'est via une macro le nom est connu
|
||||||
|
options.rollTarget = game.actors.get(options.actorId).items.get(options.rollTarget).name
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.rollType === ROLL_TYPE.ATTACK) {
|
||||||
|
damageDice = options.rollValue
|
||||||
|
}
|
||||||
|
|
||||||
|
let malus = "0"
|
||||||
|
let targetMalus = "0"
|
||||||
|
let targetName
|
||||||
|
let targetArmor
|
||||||
|
const displayOpponentMalus = game.settings.get("tenebris", "displayOpponentMalus")
|
||||||
|
|
||||||
|
if (options.rollType === ROLL_TYPE.SAVE && options.hasTarget && options.target.document.actor.type === "opponent") {
|
||||||
|
targetName = options.target.document.actor.name
|
||||||
|
if (displayOpponentMalus) malus = options.target.document.actor.system.malus.toString()
|
||||||
|
else targetMalus = options.target.document.actor.system.malus.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.rollType === ROLL_TYPE.DAMAGE && options.hasTarget && options.target.document.actor.type === "opponent") {
|
||||||
|
targetName = options.target.document.actor.name
|
||||||
|
targetArmor = options.target.document.actor.system.armure.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
let dialogContext = {
|
||||||
|
isSave: options.rollType === ROLL_TYPE.SAVE,
|
||||||
|
isResource: options.rollType === ROLL_TYPE.RESOURCE,
|
||||||
|
isDamage: options.rollType === ROLL_TYPE.DAMAGE,
|
||||||
|
isAttack: options.rollType === ROLL_TYPE.ATTACK,
|
||||||
|
rollModes,
|
||||||
|
fieldRollMode,
|
||||||
|
choiceAide,
|
||||||
|
choiceGene,
|
||||||
|
choiceAvantage,
|
||||||
|
choiceModificateur,
|
||||||
|
damageDice,
|
||||||
|
damageDiceMax,
|
||||||
|
damageDiceFinal,
|
||||||
|
damageDiceLowered,
|
||||||
|
formula,
|
||||||
|
hasTarget: options.hasTarget,
|
||||||
|
malus,
|
||||||
|
targetName,
|
||||||
|
targetArmor,
|
||||||
|
rollAdvantage: this._convertAvantages(options.rollAdvantage),
|
||||||
|
rangeAdvantage: this._convertRollAdvantageToRange(options.rollAdvantage),
|
||||||
|
}
|
||||||
|
const content = await renderTemplate("systems/fvtt-cthulhu-eternal/templates/roll-dialog.hbs", dialogContext)
|
||||||
|
|
||||||
|
const title = CthulhuEternalRoll.createTitle(options.rollType, options.rollTarget)
|
||||||
|
const label = game.i18n.localize("TENEBRIS.Roll.roll")
|
||||||
|
const rollContext = await foundry.applications.api.DialogV2.wait({
|
||||||
|
window: { title: title },
|
||||||
|
classes: ["lethalfantasy"],
|
||||||
|
content,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: label,
|
||||||
|
callback: (event, button, dialog) => {
|
||||||
|
const output = Array.from(button.form.elements).reduce((obj, input) => {
|
||||||
|
if (input.name) obj[input.name] = input.value
|
||||||
|
return obj
|
||||||
|
}, {})
|
||||||
|
// Avantages
|
||||||
|
switch (output.avantages) {
|
||||||
|
case "1":
|
||||||
|
output.avantages = "doubleDesavantage"
|
||||||
|
break
|
||||||
|
case "2":
|
||||||
|
output.avantages = "desavantage"
|
||||||
|
break
|
||||||
|
case "3":
|
||||||
|
output.avantages = "normal"
|
||||||
|
break
|
||||||
|
case "4":
|
||||||
|
output.avantages = "avantage"
|
||||||
|
break
|
||||||
|
case "5":
|
||||||
|
output.avantages = "doubleAvantage"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rejectClose: false, // Click on Close button will not launch an error
|
||||||
|
render: (event, dialog) => {
|
||||||
|
const rangeInput = dialog.querySelector('input[name="avantages"]')
|
||||||
|
if (rangeInput) {
|
||||||
|
rangeInput.addEventListener("change", (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
const readOnly = dialog.querySelector('input[name="selectAvantages"]')
|
||||||
|
readOnly.value = this._convertAvantages(event.target.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// If the user cancels the dialog, exit
|
||||||
|
if (rollContext === null) return
|
||||||
|
|
||||||
|
let treshold
|
||||||
|
|
||||||
|
if (options.rollType === ROLL_TYPE.SAVE) {
|
||||||
|
const aide = rollContext.aide === "" ? 0 : parseInt(rollContext.aide, 10)
|
||||||
|
const gene = rollContext.gene === "" ? 0 : parseInt(rollContext.gene, 10)
|
||||||
|
const modificateur = rollContext.modificateur === "" ? 0 : parseInt(rollContext.modificateur, 10)
|
||||||
|
|
||||||
|
if (options.rollType === ROLL_TYPE.SAVE) {
|
||||||
|
let dice = "1d20"
|
||||||
|
switch (rollContext.avantages) {
|
||||||
|
case "avantage":
|
||||||
|
dice = "2d20kl"
|
||||||
|
break
|
||||||
|
case "desavantage":
|
||||||
|
dice = "2d20kh"
|
||||||
|
break
|
||||||
|
case "doubleAvantage":
|
||||||
|
dice = "3d20kl"
|
||||||
|
break
|
||||||
|
case "doubleDesavantage":
|
||||||
|
dice = "3d20kh"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
formula = `${dice}`
|
||||||
|
}
|
||||||
|
|
||||||
|
treshold = options.rollValue + aide + gene + modificateur
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formula for a damage roll
|
||||||
|
if (options.rollType === ROLL_TYPE.DAMAGE) {
|
||||||
|
formula = damageDiceFinal
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formula for an attack roll
|
||||||
|
if (options.rollType === ROLL_TYPE.ATTACK) {
|
||||||
|
formula = damageDice
|
||||||
|
}
|
||||||
|
|
||||||
|
const rollData = {
|
||||||
|
type: options.rollType,
|
||||||
|
target: options.rollTarget,
|
||||||
|
value: options.rollValue,
|
||||||
|
treshold: treshold,
|
||||||
|
actorId: options.actorId,
|
||||||
|
actorName: options.actorName,
|
||||||
|
actorImage: options.actorImage,
|
||||||
|
rollMode: rollContext.visibility,
|
||||||
|
hasTarget: options.hasTarget,
|
||||||
|
targetName,
|
||||||
|
targetArmor,
|
||||||
|
targetMalus,
|
||||||
|
...rollContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook event that fires before the roll is made.
|
||||||
|
* @function tenebris.preRoll
|
||||||
|
* @memberof hookEvents
|
||||||
|
* @param {Object} options Options for the roll.
|
||||||
|
* @param {Object} rollData All data related to the roll.
|
||||||
|
* @returns {boolean} Explicitly return `false` to prevent roll to be made.
|
||||||
|
*/
|
||||||
|
if (Hooks.call("tenebris.preRoll", options, rollData) === false) return
|
||||||
|
|
||||||
|
const roll = new this(formula, options.data, rollData)
|
||||||
|
|
||||||
|
await roll.evaluate()
|
||||||
|
|
||||||
|
let resultType
|
||||||
|
if (options.rollType === ROLL_TYPE.SAVE) {
|
||||||
|
resultType = roll.total <= treshold ? "success" : "failure"
|
||||||
|
} else if (options.rollType === ROLL_TYPE.RESOURCE) {
|
||||||
|
resultType = roll.total === 1 || roll.total === 2 ? "failure" : "success"
|
||||||
|
}
|
||||||
|
|
||||||
|
let realDamage
|
||||||
|
if (options.rollType === ROLL_TYPE.DAMAGE) {
|
||||||
|
realDamage = Math.max(0, roll.total - parseInt(targetArmor, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
roll.options.resultType = resultType
|
||||||
|
roll.options.treshold = treshold
|
||||||
|
roll.options.introText = roll._createIntroText()
|
||||||
|
roll.options.introTextTooltip = roll._createIntroTextTooltip()
|
||||||
|
roll.options.realDamage = realDamage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hook event that fires after the roll has been made.
|
||||||
|
* @function tenebris.Roll
|
||||||
|
* @memberof hookEvents
|
||||||
|
* @param {Object} options Options for the roll.
|
||||||
|
* @param {Object} rollData All data related to the roll.
|
||||||
|
@param {CthulhuEternalRoll} roll The resulting roll.
|
||||||
|
* @returns {boolean} Explicitly return `false` to prevent roll to be made.
|
||||||
|
*/
|
||||||
|
if (Hooks.call("tenebris.Roll", options, rollData, roll) === false) return
|
||||||
|
|
||||||
|
return roll
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a title based on the given type.
|
||||||
|
*
|
||||||
|
* @param {string} type The type of the roll.
|
||||||
|
* @param {string} target The target of the roll.
|
||||||
|
* @returns {string} The generated title.
|
||||||
|
*/
|
||||||
|
static createTitle(type, target) {
|
||||||
|
switch (type) {
|
||||||
|
case ROLL_TYPE.SAVE:
|
||||||
|
return `${game.i18n.localize("TENEBRIS.Dialog.titleSave")} : ${game.i18n.localize(`TENEBRIS.Manager.${target}`)}`
|
||||||
|
case ROLL_TYPE.RESOURCE:
|
||||||
|
return `${game.i18n.localize("TENEBRIS.Dialog.titleResource")} : ${game.i18n.localize(`TENEBRIS.Manager.${target}`)}`
|
||||||
|
case ROLL_TYPE.DAMAGE:
|
||||||
|
return `${game.i18n.localize("TENEBRIS.Dialog.titleDamage")} : ${target}`
|
||||||
|
case ROLL_TYPE.ATTACK:
|
||||||
|
return `${game.i18n.localize("TENEBRIS.Dialog.titleAttack")} : ${target}`
|
||||||
|
default:
|
||||||
|
return game.i18n.localize("TENEBRIS.Dialog.titleStandard")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async render(chatOptions = {}) {
|
||||||
|
let chatData = await this._getChatCardData(chatOptions.isPrivate)
|
||||||
|
return await renderTemplate(this.constructor.CHAT_TEMPLATE, chatData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the data required for rendering a roll chat card.
|
||||||
|
*
|
||||||
|
* @param {boolean} isPrivate Indicates if the chat card is private.
|
||||||
|
* @returns {Promise<Object>} A promise that resolves to an object containing the chat card data.
|
||||||
|
* @property {Array<string>} css - CSS classes for the chat card.
|
||||||
|
* @property {Object} data - The data associated with the roll.
|
||||||
|
* @property {number} diceTotal - The total value of the dice rolled.
|
||||||
|
* @property {boolean} isGM - Indicates if the user is a Game Master.
|
||||||
|
* @property {string} formula - The formula used for the roll.
|
||||||
|
* @property {number} total - The total result of the roll.
|
||||||
|
* @property {boolean} isSave - Indicates if the roll is a saving throw.
|
||||||
|
* @property {boolean} isResource - Indicates if the roll is related to a resource.
|
||||||
|
* @property {boolean} isDamage - Indicates if the roll is for damage.
|
||||||
|
* @property {boolean} isFailure - Indicates if the roll is a failure.
|
||||||
|
* @property {Array} avantages - Advantages associated with the roll.
|
||||||
|
* @property {string} actorId - The ID of the actor performing the roll.
|
||||||
|
* @property {string} actingCharName - The name of the character performing the roll.
|
||||||
|
* @property {string} actingCharImg - The image of the character performing the roll.
|
||||||
|
* @property {string} introText - Introductory text for the roll.
|
||||||
|
* @property {string} introTextTooltip - Tooltip for the introductory text.
|
||||||
|
* @property {string} resultType - The type of result (e.g., success, failure).
|
||||||
|
* @property {boolean} hasTarget - Indicates if the roll has a target.
|
||||||
|
* @property {string} targetName - The name of the target.
|
||||||
|
* @property {number} targetArmor - The armor value of the target.
|
||||||
|
* @property {number} realDamage - The real damage dealt.
|
||||||
|
* @property {boolean} isPrivate - Indicates if the chat card is private.
|
||||||
|
* @property {string} cssClass - The combined CSS classes as a single string.
|
||||||
|
* @property {string} tooltip - The tooltip text for the chat card.
|
||||||
|
*/
|
||||||
|
async _getChatCardData(isPrivate) {
|
||||||
|
const cardData = {
|
||||||
|
css: [SYSTEM.id, "dice-roll"],
|
||||||
|
data: this.data,
|
||||||
|
diceTotal: this.dice.reduce((t, d) => t + d.total, 0),
|
||||||
|
isGM: game.user.isGM,
|
||||||
|
formula: this.formula,
|
||||||
|
total: this.total,
|
||||||
|
isSave: this.isSave,
|
||||||
|
isResource: this.isResource,
|
||||||
|
isDamage: this.isDamage,
|
||||||
|
isFailure: this.isFailure,
|
||||||
|
avantages: this.avantages,
|
||||||
|
actorId: this.actorId,
|
||||||
|
actingCharName: this.actorName,
|
||||||
|
actingCharImg: this.actorImage,
|
||||||
|
introText: this.introText,
|
||||||
|
introTextTooltip: this.introTextTooltip,
|
||||||
|
resultType: this.resultType,
|
||||||
|
hasTarget: this.hasTarget,
|
||||||
|
targetName: this.targetName,
|
||||||
|
targetArmor: this.targetArmor,
|
||||||
|
realDamage: this.realDamage,
|
||||||
|
isPrivate: isPrivate,
|
||||||
|
}
|
||||||
|
cardData.cssClass = cardData.css.join(" ")
|
||||||
|
cardData.tooltip = isPrivate ? "" : await this.getTooltip()
|
||||||
|
return cardData
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the roll result to a chat message.
|
||||||
|
*
|
||||||
|
* @param {Object} [messageData={}] Additional data to include in the message.
|
||||||
|
* @param {Object} options Options for message creation.
|
||||||
|
* @param {string} options.rollMode The mode of the roll (e.g., public, private).
|
||||||
|
* @param {boolean} [options.create=true] Whether to create the message.
|
||||||
|
* @returns {Promise} - A promise that resolves when the message is created.
|
||||||
|
*/
|
||||||
|
async toMessage(messageData = {}, { rollMode, create = true } = {}) {
|
||||||
|
super.toMessage(
|
||||||
|
{
|
||||||
|
isSave: this.isSave,
|
||||||
|
isResource: this.isResource,
|
||||||
|
isDamage: this.isDamage,
|
||||||
|
isFailure: this.resultType === "failure",
|
||||||
|
avantages: this.avantages,
|
||||||
|
introText: this.introText,
|
||||||
|
introTextTooltip: this.introTextTooltip,
|
||||||
|
actingCharName: this.actorName,
|
||||||
|
actingCharImg: this.actorImage,
|
||||||
|
hasTarget: this.hasTarget,
|
||||||
|
targetName: this.targetName,
|
||||||
|
targetArmor: this.targetArmor,
|
||||||
|
targetMalus: this.targetMalus,
|
||||||
|
realDamage: this.realDamage,
|
||||||
|
...messageData,
|
||||||
|
},
|
||||||
|
{ rollMode: rollMode },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used in the avantages select and with the rollAdvantage parameter: convert the selected value to the corresponding string
|
||||||
|
static _convertAvantages(value) {
|
||||||
|
switch (value) {
|
||||||
|
case "1":
|
||||||
|
return game.i18n.localize("TENEBRIS.Roll.doubleDesavantage")
|
||||||
|
case "2":
|
||||||
|
return game.i18n.localize("TENEBRIS.Roll.desavantage")
|
||||||
|
case "3":
|
||||||
|
return game.i18n.localize("TENEBRIS.Roll.normal")
|
||||||
|
case "4":
|
||||||
|
return game.i18n.localize("TENEBRIS.Roll.avantage")
|
||||||
|
case "5":
|
||||||
|
return game.i18n.localize("TENEBRIS.Roll.doubleAvantage")
|
||||||
|
case "--":
|
||||||
|
return game.i18n.localize("TENEBRIS.Roll.doubleDesavantage")
|
||||||
|
case "-":
|
||||||
|
return game.i18n.localize("TENEBRIS.Roll.desavantage")
|
||||||
|
case "=":
|
||||||
|
return game.i18n.localize("TENEBRIS.Roll.normal")
|
||||||
|
case "+":
|
||||||
|
return game.i18n.localize("TENEBRIS.Roll.avantage")
|
||||||
|
case "++":
|
||||||
|
return game.i18n.localize("TENEBRIS.Roll.doubleAvantage")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used in the rollAdvantage parameter: convert the selected value to the corresponding range value
|
||||||
|
static _convertRollAdvantageToRange(value) {
|
||||||
|
switch (value) {
|
||||||
|
case "--":
|
||||||
|
return 1
|
||||||
|
case "-":
|
||||||
|
return 2
|
||||||
|
case "=":
|
||||||
|
return 3
|
||||||
|
case "+":
|
||||||
|
return 4
|
||||||
|
case "++":
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
80
module/enrichers.mjs
Normal file
80
module/enrichers.mjs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* Enricher qui permet de transformer un texte en un lien de lancer de dés
|
||||||
|
* Pour une syntaxe de type @jet[x]{y}(z) avec x la caractéristique, y le titre et z l'avantage
|
||||||
|
* x de type rob, dex, int, per, vol pour les caractéristiques
|
||||||
|
* et de type oeil, verbe, san, bourse, magie pour les ressources
|
||||||
|
* y est le titre du jet et permet de décrire l'action
|
||||||
|
* z est l'avantage du jet, avec pour valeurs possibles : --, -, +, ++
|
||||||
|
*/
|
||||||
|
export function setupTextEnrichers() {
|
||||||
|
CONFIG.TextEditor.enrichers = CONFIG.TextEditor.enrichers.concat([
|
||||||
|
{
|
||||||
|
// eslint-disable-next-line no-useless-escape
|
||||||
|
pattern: /\@jet\[(.+?)\]{(.*?)}\((.*?)\)/gm,
|
||||||
|
enricher: async (match, options) => {
|
||||||
|
const a = document.createElement("a")
|
||||||
|
a.classList.add("ask-roll-journal")
|
||||||
|
const target = match[1]
|
||||||
|
const title = match[2]
|
||||||
|
const avantage = match[3]
|
||||||
|
|
||||||
|
let type = "resource"
|
||||||
|
if (["rob", "dex", "int", "per", "vol"].includes(target)) {
|
||||||
|
type = "save"
|
||||||
|
}
|
||||||
|
|
||||||
|
let rollAvantage = "normal"
|
||||||
|
if (avantage) {
|
||||||
|
switch (avantage) {
|
||||||
|
case "++":
|
||||||
|
rollAvantage = "++"
|
||||||
|
break
|
||||||
|
case "+":
|
||||||
|
rollAvantage = "+"
|
||||||
|
break
|
||||||
|
case "-":
|
||||||
|
rollAvantage = "-"
|
||||||
|
break
|
||||||
|
case "--":
|
||||||
|
rollAvantage = "--"
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.dataset.rollType = type
|
||||||
|
a.dataset.rollTarget = target
|
||||||
|
a.dataset.rollTitle = title
|
||||||
|
a.dataset.rollAvantage = rollAvantage
|
||||||
|
a.innerHTML = `
|
||||||
|
<i class="fas fa-dice-d20"></i> ${getLibelle(target)}${rollAvantage !== "normal" ? rollAvantage : ""}
|
||||||
|
`
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
const mapLibelles = {
|
||||||
|
rob: "ROB",
|
||||||
|
dex: "DEX",
|
||||||
|
int: "INT",
|
||||||
|
per: "PER",
|
||||||
|
vol: "VOL",
|
||||||
|
oeil: "OEIL",
|
||||||
|
verbe: "VERBE",
|
||||||
|
san: "SANTE MENTALE",
|
||||||
|
bourse: "BOURSE",
|
||||||
|
magie: "MAGIE",
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le libellé associé à la valeur qui sera affiché dans le journal
|
||||||
|
* @param {string} value
|
||||||
|
*/
|
||||||
|
function getLibelle(value) {
|
||||||
|
if (mapLibelles[value]) {
|
||||||
|
return mapLibelles[value]
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
82
module/macros.mjs
Normal file
82
module/macros.mjs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
export class Macros {
|
||||||
|
/**
|
||||||
|
* Creates a macro based on the type of data dropped onto the hotbar.
|
||||||
|
*
|
||||||
|
* @param {Object} dropData The data object representing the item dropped.
|
||||||
|
* @param {string} dropData.type The type of the dropped item (e.g., "Actor", "JournalEntry", "roll").
|
||||||
|
* @param {string} dropData.uuid The UUID of the dropped item.
|
||||||
|
* @param {string} [dropData.actorId] The ID of the actor (required if type is "roll").
|
||||||
|
* @param {string} [dropData.rollType] The type of roll (required if type is "roll").
|
||||||
|
* @param {string} [dropData.rollTarget] The target of the roll (required if type is "roll").
|
||||||
|
* @param {string} [dropData.value] The value of the roll (required if type is "roll").
|
||||||
|
* @param {number} slot The hotbar slot where the macro will be created.
|
||||||
|
*
|
||||||
|
* @returns {Promise<void>} A promise that resolves when the macro is created.
|
||||||
|
*/
|
||||||
|
static createCthulhuEternalMacro = async function (dropData, slot) {
|
||||||
|
switch (dropData.type) {
|
||||||
|
case "Actor":
|
||||||
|
const actor = await fromUuid(dropData.uuid)
|
||||||
|
const actorCommand = `game.actors.get("${actor.id}").sheet.render(true)`
|
||||||
|
this.createMacro(slot, actor.name, actorCommand, actor.img)
|
||||||
|
break
|
||||||
|
|
||||||
|
case "JournalEntry":
|
||||||
|
const journal = await fromUuid(dropData.uuid)
|
||||||
|
const journalCommand = `game.journal.get("${journal.id}").sheet.render(true)`
|
||||||
|
this.createMacro(slot, journal.name, journalCommand, journal.img ? journal.img : "icons/svg/book.svg")
|
||||||
|
break
|
||||||
|
|
||||||
|
case "roll":
|
||||||
|
const rollCommand =
|
||||||
|
dropData.rollType === "save"
|
||||||
|
? `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}', '=');`
|
||||||
|
: `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}');`
|
||||||
|
const rollName = `${game.i18n.localize("TENEBRIS.Label.jet")} ${game.i18n.localize(`TENEBRIS.Manager.${dropData.rollTarget}`)}`
|
||||||
|
this.createMacro(slot, rollName, rollCommand, "icons/svg/d20-grey.svg")
|
||||||
|
break
|
||||||
|
|
||||||
|
case "rollDamage":
|
||||||
|
const weapon = game.actors.get(dropData.actorId).items.get(dropData.rollTarget)
|
||||||
|
const rollDamageCommand = `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}');`
|
||||||
|
const rollDamageName = `${game.i18n.localize("TENEBRIS.Label.jet")} ${weapon.name}`
|
||||||
|
this.createMacro(slot, rollDamageName, rollDamageCommand, weapon.img)
|
||||||
|
break
|
||||||
|
|
||||||
|
case "rollAttack":
|
||||||
|
const rollAttackCommand = `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollValue}', '${dropData.rollTarget}');`
|
||||||
|
const rollAttackName = `${game.i18n.localize("TENEBRIS.Label.jet")} ${dropData.rollTarget}`
|
||||||
|
this.createMacro(slot, rollAttackName, rollAttackCommand, "icons/svg/d20-grey.svg")
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Handle other cases or do nothing
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a macro
|
||||||
|
* All macros are flaged with a tenebris.macro flag at true
|
||||||
|
* @param {*} slot
|
||||||
|
* @param {*} name
|
||||||
|
* @param {*} command
|
||||||
|
* @param {*} img
|
||||||
|
*/
|
||||||
|
static createMacro = async function (slot, name, command, img) {
|
||||||
|
let macro = game.macros.contents.find((m) => m.name === name && m.command === command)
|
||||||
|
if (!macro) {
|
||||||
|
macro = await Macro.create(
|
||||||
|
{
|
||||||
|
name: name,
|
||||||
|
type: "script",
|
||||||
|
img: img,
|
||||||
|
command: command,
|
||||||
|
flags: { "tenebris.macro": true },
|
||||||
|
},
|
||||||
|
{ displaySheet: false },
|
||||||
|
)
|
||||||
|
game.user.assignHotbarMacro(macro, slot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
module/models/_module.mjs
Normal file
10
module/models/_module.mjs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export { default as CthulhuEternalProtagonist } from "./protagonist.mjs"
|
||||||
|
export { default as CthulhuEternalWeapon } from "./weapon.mjs"
|
||||||
|
export { default as CthulhuEternalArcane } from "./arcane.mjs"
|
||||||
|
export { default as CthulhuEternalSkill } from "./skill.mjs"
|
||||||
|
export { default as CthulhuEternalArmor } from "./armor.mjs"
|
||||||
|
export { default as CthulhuEternalInjury } from "./injury.mjs"
|
||||||
|
export { default as CthulhuEternalMentalDisorder } from "./mentaldisorder.mjs"
|
||||||
|
export { default as CthulhuEternalBond } from "./bond.mjs"
|
||||||
|
export { default as CthulhuEternalGear } from "./gear.mjs"
|
||||||
|
export { default as CthulhuEternalMotivation } from "./motivation.mjs"
|
20
module/models/arcane.mjs
Normal file
20
module/models/arcane.mjs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { SYSTEM } from "../config/system.mjs"
|
||||||
|
export default class CthulhuEternalArcane extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
const schema = {}
|
||||||
|
|
||||||
|
schema.description = new fields.HTMLField({
|
||||||
|
required: false,
|
||||||
|
blank: true,
|
||||||
|
initial: "",
|
||||||
|
textSearch: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Arcane"]
|
||||||
|
}
|
18
module/models/armor.mjs
Normal file
18
module/models/armor.mjs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { SYSTEM } from "../config/system.mjs"
|
||||||
|
export default class CthulhuEternalArmor extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields
|
||||||
|
const schema = {}
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
|
||||||
|
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
|
schema.settings = new fields.StringField({ required: true, initial: "common", choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||||
|
schema.protection = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||||
|
schema.resourceLevel = new fields.NumberField({ required: true, initial: 0, min: 0 })
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Armor"]
|
||||||
|
}
|
17
module/models/bond.mjs
Normal file
17
module/models/bond.mjs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export default class CthulhuEternalBond extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
const schema = {}
|
||||||
|
|
||||||
|
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
|
schema.bondType = new fields.StringField({ required: true, initial: "individual", choices: SYSTEM.BOND_TYPE })
|
||||||
|
schema.value = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Bond"]
|
||||||
|
|
||||||
|
}
|
19
module/models/gear.mjs
Normal file
19
module/models/gear.mjs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { SYSTEM } from "../config/system.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalEquipment extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields
|
||||||
|
const schema = {}
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
|
||||||
|
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
|
schema.settings = new fields.StringField({ required: true, initial: "common", choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||||
|
schema.resourceLevel = new fields.NumberField({ required: true, initial: 0, min: 0 })
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Equipment"]
|
||||||
|
|
||||||
|
}
|
15
module/models/injury.mjs
Normal file
15
module/models/injury.mjs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export default class CthulhuEternalInjury extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
const schema = {}
|
||||||
|
|
||||||
|
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Gift"]
|
||||||
|
|
||||||
|
}
|
15
module/models/mentaldisorder.mjs
Normal file
15
module/models/mentaldisorder.mjs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export default class CthulhuEternalMentalDisorder extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
const schema = {}
|
||||||
|
|
||||||
|
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.MentalDisorder"]
|
||||||
|
|
||||||
|
}
|
16
module/models/motivation.mjs
Normal file
16
module/models/motivation.mjs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { SYSTEM } from "../config/system.mjs"
|
||||||
|
export default class CthulhuEternalMotivation extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields
|
||||||
|
const schema = {}
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
|
||||||
|
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Shield"]
|
||||||
|
|
||||||
|
}
|
120
module/models/protagonist.mjs
Normal file
120
module/models/protagonist.mjs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import { SYSTEM } from "../config/system.mjs"
|
||||||
|
import CthulhuEternalRoll from "../documents/roll.mjs"
|
||||||
|
|
||||||
|
export default class CthulhuEternalProtagonist extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
const schema = {}
|
||||||
|
|
||||||
|
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
|
schema.notes = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
|
|
||||||
|
// Carac
|
||||||
|
const characteristicField = (label) => {
|
||||||
|
const schema = {
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 3, min: 0 }),
|
||||||
|
percent: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 100 }),
|
||||||
|
attackMod: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
defenseMod: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}
|
||||||
|
return new fields.SchemaField(schema, { label })
|
||||||
|
}
|
||||||
|
|
||||||
|
schema.characteristics = new fields.SchemaField(
|
||||||
|
Object.values(SYSTEM.CHARACTERISTICS).reduce((obj, characteristic) => {
|
||||||
|
obj[characteristic.id] = characteristicField(characteristic.label)
|
||||||
|
return obj
|
||||||
|
}, {}),
|
||||||
|
)
|
||||||
|
|
||||||
|
schema.hp = new fields.SchemaField({
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.perception = new fields.SchemaField({
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||||
|
})
|
||||||
|
schema.grit = new fields.SchemaField({
|
||||||
|
earned: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
current: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||||
|
})
|
||||||
|
schema.luck = new fields.SchemaField({
|
||||||
|
earned: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
current: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||||
|
})
|
||||||
|
schema.movement = new fields.SchemaField({
|
||||||
|
walk: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
jog: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
sprint: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
run: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
armorAdjust: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
})
|
||||||
|
schema.biodata = new fields.SchemaField({
|
||||||
|
class: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||||
|
level: new fields.NumberField({ ...requiredInteger, initial: 1, min: 1 }),
|
||||||
|
mortal: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||||
|
alignment: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||||
|
age: new fields.NumberField({ ...requiredInteger, initial: 15, min: 6 }),
|
||||||
|
height: new fields.NumberField({ ...requiredInteger, initial: 170, min: 50 }),
|
||||||
|
eyes: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||||
|
hair: new fields.StringField({ required: true, nullable: false, initial: "" })
|
||||||
|
})
|
||||||
|
schema.developmentPoints = new fields.SchemaField({
|
||||||
|
total: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
remaining: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||||
|
})
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Protagonist"]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rolls a dice for a character.
|
||||||
|
* @param {("save"|"resource|damage")} rollType The type of the roll.
|
||||||
|
* @param {number} rollTarget The target value for the roll. Which caracteristic or resource. If the roll is a damage roll, this is the id of the item.
|
||||||
|
* @param {"="|"+"|"++"|"-"|"--"} rollAdvantage If there is an avantage (+), a disadvantage (-), a double advantage (++), a double disadvantage (--) or a normal roll (=).
|
||||||
|
* @returns {Promise<null>} - A promise that resolves to null if the roll is cancelled.
|
||||||
|
*/
|
||||||
|
async roll(rollType, rollTarget, rollAdvantage = "=") {
|
||||||
|
let rollValue
|
||||||
|
let opponentTarget
|
||||||
|
switch (rollType) {
|
||||||
|
default:
|
||||||
|
// Handle other cases or do nothing
|
||||||
|
break
|
||||||
|
}
|
||||||
|
await this._roll(rollType, rollTarget, rollValue, opponentTarget, rollAdvantage)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rolls a dice for a character.
|
||||||
|
* @param {("save"|"resource|damage")} rollType The type of the roll.
|
||||||
|
* @param {number} rollTarget The target value for the roll. Which caracteristic or resource. If the roll is a damage roll, this is the id of the item.
|
||||||
|
* @param {number} rollValue The value of the roll. If the roll is a damage roll, this is the dice to roll.
|
||||||
|
* @param {Token} opponentTarget The target of the roll : used for save rolls to get the oppponent's malus.
|
||||||
|
* @param {"="|"+"|"++"|"-"|"--"} rollAdvantage If there is an avantage (+), a disadvantage (-), a double advantage (++), a double disadvantage (--) or a normal roll (=).
|
||||||
|
* @returns {Promise<null>} - A promise that resolves to null if the roll is cancelled.
|
||||||
|
*/
|
||||||
|
async _roll(rollType, rollTarget, rollValue, opponentTarget = undefined, rollAdvantage = "=") {
|
||||||
|
const hasTarget = opponentTarget !== undefined
|
||||||
|
let roll = await CthulhuEternalRoll.prompt({
|
||||||
|
rollType,
|
||||||
|
rollTarget,
|
||||||
|
rollValue,
|
||||||
|
actorId: this.parent.id,
|
||||||
|
actorName: this.parent.name,
|
||||||
|
actorImage: this.parent.img,
|
||||||
|
hasTarget,
|
||||||
|
target: opponentTarget,
|
||||||
|
rollAdvantage,
|
||||||
|
})
|
||||||
|
if (!roll) return null
|
||||||
|
|
||||||
|
await roll.toMessage({}, { rollMode: roll.options.rollMode })
|
||||||
|
}
|
||||||
|
}
|
65
module/models/skill.mjs
Normal file
65
module/models/skill.mjs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { SYSTEM } from "../config/system.mjs"
|
||||||
|
export default class LethalFantasySkill extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields
|
||||||
|
const schema = {}
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
|
||||||
|
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
|
schema.settings = new fields.StringField({ required: true, initial: "common", choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||||
|
|
||||||
|
schema.base = new fields.StringField({ required: true, initial: "WIS" })
|
||||||
|
schema.bonus = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||||
|
schema.diceEvolved = new fields.BooleanField({ required: true, initial: true })
|
||||||
|
schema.rollFailed = new fields.BooleanField({ required: true, initial: false })
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Skill"]
|
||||||
|
|
||||||
|
|
||||||
|
prepareDerivedData() {
|
||||||
|
super.prepareDerivedData();
|
||||||
|
this.skillTotal = this.computeBase();
|
||||||
|
}
|
||||||
|
|
||||||
|
computeBase() {
|
||||||
|
let actor = this.parent?.actor;
|
||||||
|
if (!actor) {
|
||||||
|
return `${this.base } + ${ String(this.bonus)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the base value per stat : WIS,DEX,STR,INT,CHA (example)
|
||||||
|
const base = this.base;
|
||||||
|
let baseSplit = base.split(",");
|
||||||
|
let baseSplitLength = baseSplit.length;
|
||||||
|
if ( baseSplitLength > 0) {
|
||||||
|
// Select the max stat value from the parent actor
|
||||||
|
let maxStat = 0;
|
||||||
|
for (let i = 0; i < baseSplitLength; i++) {
|
||||||
|
const stat = baseSplit[i];
|
||||||
|
const statValue = actor.system.characteristics[stat.toLowerCase()]?.value || 0;
|
||||||
|
if (statValue > maxStat) {
|
||||||
|
maxStat = statValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxStat;
|
||||||
|
} else {
|
||||||
|
// Split with + calculate the total
|
||||||
|
baseSplit = base.split("+");
|
||||||
|
baseSplitLength = baseSplit.length;
|
||||||
|
if ( baseSplitLength > 0) {
|
||||||
|
let total = 0;
|
||||||
|
for (let i = 0; i < baseSplitLength; i++) {
|
||||||
|
const stat = baseSplit[i];
|
||||||
|
const statValue = actor.system.characteristics[stat.toLowerCase()]?.value || 0;
|
||||||
|
total += statValue;
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return `${this.base } + ${ String(this.bonus)}`;
|
||||||
|
}
|
||||||
|
}
|
30
module/models/weapon.mjs
Normal file
30
module/models/weapon.mjs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { SYSTEM } from "../config/system.mjs"
|
||||||
|
|
||||||
|
export default class LethalFantasySkill extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields
|
||||||
|
const schema = {}
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
|
||||||
|
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
|
schema.settings = new fields.StringField({ required: true, initial: "common", choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||||
|
|
||||||
|
schema.weaponType = new fields.StringField({ required: true, initial: "melee", choices: SYSTEM.WEAPON_TYPE })
|
||||||
|
schema.damage = new fields.StringField({required: true, initial: "1d6"})
|
||||||
|
schema.baseRange = new fields.StringField({required: true, initial: ""})
|
||||||
|
schema.rangeDistance = new fields.StringField({ required: true, initial: "yard", choices: SYSTEM.WEAPON_RANGE_UNIT })
|
||||||
|
schema.lethality = new fields.NumberField({ required: true, initial: 0, min: 0 })
|
||||||
|
schema.killRadius = new fields.NumberField({ required: true, initial: 0, min: 0 })
|
||||||
|
|
||||||
|
schema.resourceLevel = new fields.NumberField({ required: true, initial: 0, min: 0 })
|
||||||
|
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Weapon"]
|
||||||
|
|
||||||
|
get weaponCategory() {
|
||||||
|
return game.i18n.localize(CATEGORY[this.category].label)
|
||||||
|
}
|
||||||
|
}
|
32
module/socket.mjs
Normal file
32
module/socket.mjs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Handles socket events based on the provided action.
|
||||||
|
*
|
||||||
|
* @param {Object} [params={}] The parameters for the socket event.
|
||||||
|
* @param {string|null} [params.action=null] The action to be performed.
|
||||||
|
* @param {Object} [params.data={}] The data associated with the action.
|
||||||
|
* @returns {*} The result of the action handler, if applicable.
|
||||||
|
*/
|
||||||
|
export function handleSocketEvent({ action = null, data = {} } = {}) {
|
||||||
|
console.debug("handleSocketEvent", action, data)
|
||||||
|
switch (action) {
|
||||||
|
case "fortune":
|
||||||
|
return CthulhuEternalFortune.handleSocketEvent(data)
|
||||||
|
case "askRoll":
|
||||||
|
return _askRoll(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the socket event to ask for a roll.
|
||||||
|
*
|
||||||
|
* @param {Object} [options={}] The options object.
|
||||||
|
* @param {string} [options.userId] The ID of the user who initiated the roll.
|
||||||
|
*/
|
||||||
|
export function _askRoll({ userId } = {}) {
|
||||||
|
console.debug(`handleSocketEvent _askRoll from ${userId} !`)
|
||||||
|
const currentUser = game.user._id
|
||||||
|
if (userId === currentUser) {
|
||||||
|
foundry.audio.AudioHelper.play({ src: "/systems/fvtt-cthulhu-eternal/sounds/drums.wav", volume: 0.8, autoplay: true, loop: false }, false)
|
||||||
|
}
|
||||||
|
}
|
4
module/utils.mjs
Normal file
4
module/utils.mjs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
export default class CthulhuEternalUtils {
|
||||||
|
|
||||||
|
}
|
1
node_modules/.bin/acorn
generated
vendored
Symbolic link
1
node_modules/.bin/acorn
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../acorn/bin/acorn
|
1
node_modules/.bin/errno
generated
vendored
Symbolic link
1
node_modules/.bin/errno
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../errno/cli.js
|
1
node_modules/.bin/eslint
generated
vendored
Symbolic link
1
node_modules/.bin/eslint
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../eslint/bin/eslint.js
|
1
node_modules/.bin/eslint-config-prettier
generated
vendored
Symbolic link
1
node_modules/.bin/eslint-config-prettier
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../eslint-config-prettier/bin/cli.js
|
1
node_modules/.bin/fvtt
generated
vendored
Symbolic link
1
node_modules/.bin/fvtt
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../@foundryvtt/foundryvtt-cli/fvtt.mjs
|
1
node_modules/.bin/gulp
generated
vendored
Symbolic link
1
node_modules/.bin/gulp
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../gulp/bin/gulp.js
|
1
node_modules/.bin/image-size
generated
vendored
Symbolic link
1
node_modules/.bin/image-size
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../image-size/bin/image-size.js
|
1
node_modules/.bin/js-yaml
generated
vendored
Symbolic link
1
node_modules/.bin/js-yaml
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../js-yaml/bin/js-yaml.js
|
1
node_modules/.bin/lessc
generated
vendored
Symbolic link
1
node_modules/.bin/lessc
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../less/bin/lessc
|
1
node_modules/.bin/mime
generated
vendored
Symbolic link
1
node_modules/.bin/mime
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../mime/cli.js
|
1
node_modules/.bin/mkdirp
generated
vendored
Symbolic link
1
node_modules/.bin/mkdirp
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../mkdirp/dist/cjs/src/bin.js
|
1
node_modules/.bin/needle
generated
vendored
Symbolic link
1
node_modules/.bin/needle
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../needle/bin/needle
|
1
node_modules/.bin/node-gyp-build
generated
vendored
Symbolic link
1
node_modules/.bin/node-gyp-build
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../node-gyp-build/bin.js
|
1
node_modules/.bin/node-gyp-build-optional
generated
vendored
Symbolic link
1
node_modules/.bin/node-gyp-build-optional
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../node-gyp-build/optional.js
|
1
node_modules/.bin/node-gyp-build-test
generated
vendored
Symbolic link
1
node_modules/.bin/node-gyp-build-test
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../node-gyp-build/build-test.js
|
1
node_modules/.bin/node-which
generated
vendored
Symbolic link
1
node_modules/.bin/node-which
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../which/bin/node-which
|
1
node_modules/.bin/prettier
generated
vendored
Symbolic link
1
node_modules/.bin/prettier
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../prettier/bin/prettier.cjs
|
1
node_modules/.bin/resolve
generated
vendored
Symbolic link
1
node_modules/.bin/resolve
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../resolve/bin/resolve
|
1
node_modules/.bin/semver
generated
vendored
Symbolic link
1
node_modules/.bin/semver
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../semver/bin/semver.js
|
3465
node_modules/.package-lock.json
generated
vendored
Normal file
3465
node_modules/.package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
589
node_modules/@es-joy/jsdoccomment/CHANGES.md
generated
vendored
Normal file
589
node_modules/@es-joy/jsdoccomment/CHANGES.md
generated
vendored
Normal file
@ -0,0 +1,589 @@
|
|||||||
|
# CHANGES for `@es-joy/jsdoccomment`
|
||||||
|
|
||||||
|
## 0.46.0
|
||||||
|
|
||||||
|
- chore: update esquery, drop bundling of types, update devDeps
|
||||||
|
|
||||||
|
## 0.45.0
|
||||||
|
|
||||||
|
- feat: get following comment (experimental)
|
||||||
|
|
||||||
|
## 0.44.0
|
||||||
|
|
||||||
|
- feat: add `getNonJsdocComment` for getting non-JSDoc comments above node
|
||||||
|
|
||||||
|
## 0.43.1
|
||||||
|
|
||||||
|
- fix: for `@template` name parsing, ensure (default-)bracketed name is not broken with internal spaces.
|
||||||
|
|
||||||
|
## 0.43.0
|
||||||
|
|
||||||
|
This release brings surgical round trip parsing to generated AST and reconstruction of JSDoc comment blocks via: `parseComment` ->
|
||||||
|
`commentParserToESTree` -> `estreeToString`.
|
||||||
|
|
||||||
|
- feat: new option `spacing` for `commentParserToESTree`; the default is `compact` removing empty description lines.
|
||||||
|
Set to `preserve` to retain empty description lines.
|
||||||
|
- feat: new properties in the `JsdocBlock` generated AST `delimiterLineBreak` and `preterminalLineBreak` that encode
|
||||||
|
any line break after the opening `delimiter` and before the closing `terminal` string. Values are either `\n` or an
|
||||||
|
empty string.
|
||||||
|
|
||||||
|
- chore: update devDeps / switch to Vitest.
|
||||||
|
|
||||||
|
- New [API documentation](https://es-joy.github.io/jsdoccomment/).
|
||||||
|
|
||||||
|
Thanks:
|
||||||
|
- [@typhonrt](https://github.com/typhonrt)
|
||||||
|
|
||||||
|
## 0.42.0
|
||||||
|
|
||||||
|
- feat: expand argument for `parseComment` to accept a comment token string ([@typhonrt](https://github.com/typhonrt))
|
||||||
|
- chore: update devDeps.
|
||||||
|
|
||||||
|
## 0.41.0
|
||||||
|
|
||||||
|
- feat: look above surrounding parenthesis tokens for comment blocks, even if on a higher line than the corresponding AST structure
|
||||||
|
- chore: update comment-parser and devDeps.
|
||||||
|
|
||||||
|
## 0.40.1
|
||||||
|
|
||||||
|
- chore(TS): fix path issue
|
||||||
|
|
||||||
|
## 0.40.0
|
||||||
|
|
||||||
|
- chore: update comment-parser and devDeps.
|
||||||
|
- chore(TS): switch to NodeNext
|
||||||
|
|
||||||
|
## 0.39.4
|
||||||
|
|
||||||
|
- fix: include type exports for full inlineTags (and line) property support on blocks and tags
|
||||||
|
|
||||||
|
## 0.39.3
|
||||||
|
|
||||||
|
- fix: add type details for Node range and settings
|
||||||
|
|
||||||
|
## 0.39.2
|
||||||
|
|
||||||
|
- fix: export additional typedefs from index.js
|
||||||
|
|
||||||
|
## 0.39.1
|
||||||
|
|
||||||
|
- fix: typing export
|
||||||
|
|
||||||
|
## 0.39.0
|
||||||
|
|
||||||
|
- feat: types for test files and emit declaration files
|
||||||
|
- fix(estreeToString): add `JsdodInlineTag` stringify support
|
||||||
|
- refactor: lint
|
||||||
|
- docs: add `JsdocInlineTag` to README
|
||||||
|
- chore: update devDeps.
|
||||||
|
|
||||||
|
## 0.38.0
|
||||||
|
|
||||||
|
- feat: add parsing inline tags (#12); fixes #11
|
||||||
|
|
||||||
|
## 0.37.1
|
||||||
|
|
||||||
|
- chore: support Node 20
|
||||||
|
- chore: update esquery, devDeps.
|
||||||
|
|
||||||
|
## 0.37.0
|
||||||
|
## 0.37.0-pre.0
|
||||||
|
|
||||||
|
- fix: update `jsdoc-type-pratt-parser` (supports bracket indexes)
|
||||||
|
|
||||||
|
## 0.36.1
|
||||||
|
|
||||||
|
- fix(`getReducedASTNode`): stop checking for comment blocks at return
|
||||||
|
statement
|
||||||
|
|
||||||
|
## 0.36.0
|
||||||
|
|
||||||
|
- feat: add `hasPreterminalTagDescription` property
|
||||||
|
- fix: avoid description line properties if tag is present
|
||||||
|
- fix: ensure description and description lines added to terminal multi-line tag
|
||||||
|
|
||||||
|
## 0.35.0
|
||||||
|
|
||||||
|
- feat: add `hasPreterminalDescription` property
|
||||||
|
- fix: allow newline even for 1st line (after 0th)
|
||||||
|
|
||||||
|
## 0.34.0
|
||||||
|
|
||||||
|
- feat: add `descriptionStartLine` and `descriptionEndLine` properties
|
||||||
|
- fix: avoid duplication with 0 line comments
|
||||||
|
- chore: update devDeps.
|
||||||
|
|
||||||
|
## 0.33.4
|
||||||
|
|
||||||
|
- chore: republish as npm seems to have missed the release
|
||||||
|
|
||||||
|
## 0.33.3
|
||||||
|
|
||||||
|
- fix: ensure multi-line `description` includes newline except for
|
||||||
|
initial line descriptions
|
||||||
|
|
||||||
|
## 0.33.2
|
||||||
|
|
||||||
|
- fix: avoid repetition within multi-line descriptions
|
||||||
|
|
||||||
|
## 0.33.1
|
||||||
|
|
||||||
|
- fix: add to default no types: `description`, `example`, `file`,
|
||||||
|
`fileoverview`, `license`, `overview`, `see`, `summary`
|
||||||
|
- fix: add to no names: `file`, `fileoverview, `overview`
|
||||||
|
|
||||||
|
## 0.33.0
|
||||||
|
|
||||||
|
- chore: add Node 19 to `engines` (@RodEsp)
|
||||||
|
- chore: update devDeps. and build file accordingly
|
||||||
|
|
||||||
|
## 0.32.0
|
||||||
|
|
||||||
|
- feat: have comment checking stop at assignment patterns (comments for
|
||||||
|
defaults should not rise to function itself)
|
||||||
|
- chore: bump devDeps.
|
||||||
|
|
||||||
|
## 0.31.0
|
||||||
|
|
||||||
|
- feat: support default values with `@template` per
|
||||||
|
<https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#template>
|
||||||
|
|
||||||
|
## 0.30.0
|
||||||
|
|
||||||
|
- chore: bump `jsdoc-type-pratt-parser` and devDeps.
|
||||||
|
|
||||||
|
## 0.29.0
|
||||||
|
|
||||||
|
- fix: update `engines` as per current `getJSDocComment` behavior
|
||||||
|
- chore: update devDeps.
|
||||||
|
|
||||||
|
## 0.28.1
|
||||||
|
|
||||||
|
- fix(`getReducedASTNode`): token checking
|
||||||
|
- build: add Node 18 support (@WikiRik)
|
||||||
|
|
||||||
|
## 0.28.0
|
||||||
|
|
||||||
|
- chore: bump `engines` to support Node 18
|
||||||
|
|
||||||
|
## 0.27.0
|
||||||
|
|
||||||
|
- chore: bump `jsdoc-type-pratt-parser` and devDeps.
|
||||||
|
|
||||||
|
## 0.26.1
|
||||||
|
|
||||||
|
- fix(`estreeToString`): ensure `typeLines` may be picked up
|
||||||
|
|
||||||
|
## 0.26.0
|
||||||
|
|
||||||
|
- feat(`getJSDocComment`): allow function to detect comments just preceding a
|
||||||
|
parenthesized expression (these have no special AST but their tokens
|
||||||
|
have to be overpassed)
|
||||||
|
|
||||||
|
## 0.25.0
|
||||||
|
|
||||||
|
- feat(`parseComment`): properly support whitespace
|
||||||
|
- fix(`estreeToString`): carriage return placement for ending of JSDoc block
|
||||||
|
- fix(`commentParserToESTree`): avoid adding initial space before a tag if on
|
||||||
|
a single line
|
||||||
|
- test: make tests more accurate to jsdoc semantically
|
||||||
|
|
||||||
|
## 0.24.0
|
||||||
|
|
||||||
|
- feat(`estreeToString`): support stringification of `parsedType` but with
|
||||||
|
a new `preferRawType` option allowing the old behavior of using `rawType`
|
||||||
|
|
||||||
|
## 0.23.6
|
||||||
|
|
||||||
|
- fix(`commentParserToESTree`): ensure `postType` added after multi-line type
|
||||||
|
- fix(`estreeToString`): ensure `JsdocTypeLine` stringified with `initial` and
|
||||||
|
that they are joined together with newlines
|
||||||
|
|
||||||
|
## 0.23.5
|
||||||
|
|
||||||
|
- fix(`commentParserToESTree`): avoid duplicating tag names
|
||||||
|
|
||||||
|
## 0.23.4
|
||||||
|
|
||||||
|
- fix(`estreeToString`): add `delimiter`, etc. if adding `JsdocDescriptionLine`
|
||||||
|
for `JsdocBlock`
|
||||||
|
- fix(`estreeToString`): add line break when tags are present (unless already
|
||||||
|
ending in newline)
|
||||||
|
|
||||||
|
## 0.23.3
|
||||||
|
|
||||||
|
- fix(`estreeToString`): handle multi-line block descriptions followed by
|
||||||
|
tags with line break
|
||||||
|
|
||||||
|
## 0.23.2
|
||||||
|
|
||||||
|
- fix: ensure JsdocBlock stringifier has any initial whitespace on end line
|
||||||
|
|
||||||
|
## 0.23.1
|
||||||
|
|
||||||
|
- docs(README): update
|
||||||
|
|
||||||
|
## 0.23.0
|
||||||
|
|
||||||
|
- BREAKING CHANGE(`commentParserToESTree`): rename `start` and `end` to
|
||||||
|
`initial` and `terminal` to avoid any conflicts with Acorn-style parsers
|
||||||
|
- feat: add `initial` and `terminal` on `JsdocBlock`
|
||||||
|
|
||||||
|
## 0.22.2
|
||||||
|
|
||||||
|
- fix: preserve type tokens
|
||||||
|
- perf: cache tokenizers
|
||||||
|
|
||||||
|
## 0.22.1
|
||||||
|
|
||||||
|
- fix: ensure `getJSDocComment` does not treat block comments as JSDoc unless
|
||||||
|
their first asterisk is followed by whitespace
|
||||||
|
|
||||||
|
## 0.22.0
|
||||||
|
|
||||||
|
- fix: update dep. `jsdoc-type-pratt-parser`
|
||||||
|
- chore: update `comment-parser` and simplify as possible
|
||||||
|
|
||||||
|
## 0.21.2
|
||||||
|
|
||||||
|
- fix: only throw if the raw type is not empty
|
||||||
|
|
||||||
|
## 0.21.1
|
||||||
|
|
||||||
|
- fix: provide clearer error message for `throwOnTypeParsingErrors`
|
||||||
|
|
||||||
|
## 0.21.0
|
||||||
|
|
||||||
|
- feat: add `throwOnTypeParsingErrors` to receive run-time type parsing errors
|
||||||
|
for `parsedType`
|
||||||
|
- chore: update jsdoc-type-pratt-parser and devDeps.; also lints
|
||||||
|
|
||||||
|
## 0.20.1
|
||||||
|
|
||||||
|
- fix: resume catching bad parsed type (at least until
|
||||||
|
`jsdoc-type-pratt-parser` may support all expected types)
|
||||||
|
|
||||||
|
## 0.20.0
|
||||||
|
|
||||||
|
- feat: add estree stringifer
|
||||||
|
- fix: properly supports `name`/`postName` for multi-line type
|
||||||
|
- fix: allow pratt parser to fail (unless empty)
|
||||||
|
- fix: don't add tag postDelimiter when on 0 description line
|
||||||
|
- fix: avoid adding extra line when only name and no succeeding description
|
||||||
|
- docs: clarify re: `kind`
|
||||||
|
- test: add `parsedType` with correct mode; add tests
|
||||||
|
- chore: updates jsdoc-type-pratt-parser
|
||||||
|
- chore: updates devDeps.
|
||||||
|
|
||||||
|
## 0.19.0
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- feat: treat `@kind` as having no name
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- docs: jsdoc
|
||||||
|
- test: begin checking `jsdoccomment`
|
||||||
|
- test: adds lcov reporter and open script for it
|
||||||
|
- chore: update devDeps.
|
||||||
|
|
||||||
|
## 0.18.0
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- feat: add non-visitable `endLine` property (so can detect line number
|
||||||
|
when no description present)
|
||||||
|
- feat: supply `indent` default for `parseComment`
|
||||||
|
- fix: ensure `postName` gets a space for `@template` with a description
|
||||||
|
- fix: converting JSDoc comment with tag on same line as end (e.g., single
|
||||||
|
line) to AST
|
||||||
|
- chore: update `jsdoc-type-pratt-parser`
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- docs: add jsdoc blocks internally
|
||||||
|
- chore: update devDeps.
|
||||||
|
- test: avoid need for `expect`
|
||||||
|
- test: complete coverage for `commentHandler`, `parseComment` tests
|
||||||
|
|
||||||
|
## 0.17.0
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- Enhancement: Re-export `jsdoc-type-pratt-parser`
|
||||||
|
- Update: `jsdoc-type-pratt-parser` to 2.2.1
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.16.0
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- Update: `jsdoc-type-pratt-parser` to 2.2.0
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.15.0
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- Update: `jsdoc-type-pratt-parser` to 2.1.0
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.14.2
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- Fix: Find comments previous to parentheses (used commonly in TypeScript)
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.14.1
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- Update: `jsdoc-type-pratt-parser` to 2.0.2
|
||||||
|
|
||||||
|
## 0.14.0
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- Update: `jsdoc-type-pratt-parser` to 2.0.1
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.13.0
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- Update: `comment-parser` to 1.3.0
|
||||||
|
- Fix: Allow comment on `ExportDefaultDeclaration`
|
||||||
|
|
||||||
|
## 0.12.0
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- Update: `jsdoc-type-pratt-parser` to 2.0.0
|
||||||
|
- Enhancement: Support Node 17 (@timgates42)
|
||||||
|
- Docs: Typo (@timgates42)
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- Linting: As per latest ash-nazg
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.11.0
|
||||||
|
|
||||||
|
- Update: For `@typescript/eslint-parser@5`, add `PropertyDefinition`
|
||||||
|
|
||||||
|
## 0.10.8
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- npm: Liberalize `engines` as per `comment-parser` change
|
||||||
|
- npm: Bump `comment-parser`
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- Linting: As per latest ash-nazg
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.10.7
|
||||||
|
|
||||||
|
- npm: Update comment-parser with CJS fix and re-exports
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.10.6
|
||||||
|
|
||||||
|
- Fix: Ensure copying latest build of `comment-parser`'s ESM utils
|
||||||
|
|
||||||
|
## 0.10.5
|
||||||
|
|
||||||
|
- npm: Bump fixed `jsdoc-type-pratt-parser` and devDeps.
|
||||||
|
|
||||||
|
## 0.10.4
|
||||||
|
|
||||||
|
- Fix: Bundle `comment-parser` nested imports so that IDEs (like Atom)
|
||||||
|
bundling older Node versions can still work. Still mirroring the
|
||||||
|
stricter `comment-parser` `engines` for now, however.
|
||||||
|
|
||||||
|
## 0.10.3
|
||||||
|
|
||||||
|
- npm: Avoid exporting nested subpaths for sake of older Node versions
|
||||||
|
|
||||||
|
## 0.10.2
|
||||||
|
|
||||||
|
- npm: Specify exact supported range: `^12.20 || ^14.14.0 || ^16`
|
||||||
|
|
||||||
|
## 0.10.1
|
||||||
|
|
||||||
|
- npm: Apply patch version of `comment-parser`
|
||||||
|
|
||||||
|
## 0.10.0
|
||||||
|
|
||||||
|
- npm: Point to stable `comment-parser`
|
||||||
|
|
||||||
|
## 0.9.0-alpha.6
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- Update: For `comment-parser` update, add `lineEnd`
|
||||||
|
|
||||||
|
## 0.9.0-alpha.5
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- npm: Bump `comment-parser` (for true ESM)
|
||||||
|
- Update: Remove extensions for packages for native ESM in `comment-parser` fix
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.9.0-alpha.4
|
||||||
|
|
||||||
|
- Docs: Update repo info in `package.json`
|
||||||
|
|
||||||
|
## 0.9.0-alpha.3
|
||||||
|
|
||||||
|
- Fix: Due to `comment-parser` still needing changes, revert for now to alpha.1
|
||||||
|
|
||||||
|
## 0.9.0-alpha.2
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- npm: Bump `comment-parser` (for true ESM)
|
||||||
|
- Update: Remove extensions for packages for native ESM in `comment-parser` fix
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.9.0-alpha.1
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- Breaking change: Indicate minimum for `engines` as Node >= 12
|
||||||
|
- npm: Bump `comment-parser`
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- npm: Lint cjs files
|
||||||
|
- npm: Fix eslint script
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
|
||||||
|
### User-impacting
|
||||||
|
|
||||||
|
- npm: Update `jsdoc-type-pratt-parser` (prerelease to stable patch)
|
||||||
|
|
||||||
|
### Dev-impacting
|
||||||
|
|
||||||
|
- npm: Update devDeps.
|
||||||
|
|
||||||
|
## 0.8.0-alpha.2
|
||||||
|
|
||||||
|
- Fix: Avoid erring with missing `typeLines`
|
||||||
|
|
||||||
|
## 0.8.0-alpha.1
|
||||||
|
|
||||||
|
- Breaking change: Export globally as `JsdocComment`
|
||||||
|
- Breaking change: Change `JSDoc` prefixes of all node types to `Jsdoc`
|
||||||
|
- Breaking change: Drop `jsdoctypeparserToESTree`
|
||||||
|
- Breaking enhancement: Switch to `jsdoc-type-pratt-parser` (toward greater
|
||||||
|
TypeScript expressivity and compatibility/support with catharsis)
|
||||||
|
- Enhancement: Export `jsdocTypeVisitorKeys` (from `jsdoc-type-pratt-parser`)
|
||||||
|
|
||||||
|
## 0.7.2
|
||||||
|
|
||||||
|
- Fix: Add `@description` to `noNames`
|
||||||
|
|
||||||
|
## 0.7.1
|
||||||
|
|
||||||
|
- Fix: Add `@summary` to `noNames`
|
||||||
|
|
||||||
|
## 0.7.0
|
||||||
|
|
||||||
|
- Enhancement: Allow specifying `noNames` and `noTypes` on `parseComment`
|
||||||
|
to override (or add to) tags which should have no names or types.
|
||||||
|
- Enhancement: Export `hasSeeWithLink` utility and `defaultNoTypes` and
|
||||||
|
`defaultNoNames`.
|
||||||
|
|
||||||
|
## 0.6.0
|
||||||
|
|
||||||
|
- Change `comment-parser` `tag` AST to avoid initial `@`
|
||||||
|
|
||||||
|
## 0.5.1
|
||||||
|
|
||||||
|
- Fix: Avoid setting `variation` name (just the description) (including in
|
||||||
|
dist)
|
||||||
|
- npm: Add `prepublishOnly` script
|
||||||
|
|
||||||
|
## 0.5.0
|
||||||
|
|
||||||
|
- Fix: Avoid setting `variation` name (just the description)
|
||||||
|
|
||||||
|
## 0.4.4
|
||||||
|
|
||||||
|
- Fix: Avoid setting `name` and `description` for simple `@template SomeName`
|
||||||
|
|
||||||
|
## 0.4.3
|
||||||
|
|
||||||
|
- npm: Ignores Github file
|
||||||
|
|
||||||
|
## 0.4.2
|
||||||
|
|
||||||
|
- Fix: Ensure replacement of camel-casing (used in `jsdoctypeparser` nodes and
|
||||||
|
visitor keys is global. The practical effect is that
|
||||||
|
`JSDocTypeNamed_parameter` -> `JSDocTypeNamedParameter`,
|
||||||
|
`JSDocTypeRecord_entry` -> `JSDocTypeRecordEntry`
|
||||||
|
`JSDocTypeNot_nullable` -> `JSDocTypeNotNullable`
|
||||||
|
`JSDocTypeInner_member` -> `JSDocTypeInnerMember`
|
||||||
|
`JSDocTypeInstance_member` -> `JSDocTypeInstanceMember`
|
||||||
|
`JSDocTypeString_value` -> `JSDocTypeStringValue`
|
||||||
|
`JSDocTypeNumber_value` -> `JSDocTypeNumberValue`
|
||||||
|
`JSDocTypeFile_path` -> `JSDocTypeFilePath`
|
||||||
|
`JSDocTypeType_query` -> `JSDocTypeTypeQuery`
|
||||||
|
`JSDocTypeKey_query` -> `JSDocTypeKeyQuery`
|
||||||
|
- Fix: Add missing `JSDocTypeLine` to visitor keys
|
||||||
|
- Docs: Explain AST structure/differences
|
||||||
|
|
||||||
|
## 0.4.1
|
||||||
|
|
||||||
|
- Docs: Indicate available methods with brief summary on README
|
||||||
|
|
||||||
|
## 0.4.0
|
||||||
|
|
||||||
|
- Enhancement: Expose `parseComment` and `getTokenizers`.
|
||||||
|
|
||||||
|
## 0.3.0
|
||||||
|
|
||||||
|
- Enhancement: Expose `toCamelCase` as new method rather than within a
|
||||||
|
utility file.
|
||||||
|
|
||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
- Enhancement: Exposes new methods: `commentHandler`,
|
||||||
|
`commentParserToESTree`, `jsdocVisitorKeys`, `jsdoctypeparserToESTree`,
|
||||||
|
`jsdocTypeVisitorKeys`,
|
||||||
|
|
||||||
|
## 0.1.1
|
||||||
|
|
||||||
|
- Build: Add Babel to work with earlier Node
|
||||||
|
|
||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
- Initial version
|
20
node_modules/@es-joy/jsdoccomment/LICENSE-MIT.txt
generated
vendored
Normal file
20
node_modules/@es-joy/jsdoccomment/LICENSE-MIT.txt
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Copyright JS Foundation and other contributors, https://js.foundation
|
||||||
|
Copyright (c) 2021 Brett Zamir
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
241
node_modules/@es-joy/jsdoccomment/README.md
generated
vendored
Normal file
241
node_modules/@es-joy/jsdoccomment/README.md
generated
vendored
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
# @es-joy/jsdoccomment
|
||||||
|
|
||||||
|
[![NPM](https://img.shields.io/npm/v/@es-joy/jsdoccomment.svg?label=npm)](https://www.npmjs.com/package/@es-joy/jsdoccomment)
|
||||||
|
[![License](https://img.shields.io/badge/license-MIT-yellowgreen.svg?style=flat)](https://github.com/es-joy/jsdoccomment/blob/main/LICENSE-MIT.txt)
|
||||||
|
[![Build Status](https://github.com/es-joy/jsdoccomment/workflows/CI/CD/badge.svg)](#)
|
||||||
|
[![API Docs](https://img.shields.io/badge/API%20Documentation-476ff0)](https://es-joy.github.io/jsdoccomment/)
|
||||||
|
|
||||||
|
|
||||||
|
This project aims to preserve and expand upon the
|
||||||
|
`SourceCode#getJSDocComment` functionality of the deprecated ESLint method.
|
||||||
|
|
||||||
|
It also exports a number of functions currently for working with JSDoc:
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### `parseComment`
|
||||||
|
|
||||||
|
For parsing `comment-parser` in a JSDoc-specific manner.
|
||||||
|
Might wish to have tags with or without tags, etc. derived from a split off
|
||||||
|
JSON file.
|
||||||
|
|
||||||
|
### `commentParserToESTree`
|
||||||
|
|
||||||
|
Converts [comment-parser](https://github.com/syavorsky/comment-parser)
|
||||||
|
AST to ESTree/ESLint/Babel friendly AST. See the "ESLint AST..." section below.
|
||||||
|
|
||||||
|
### `estreeToString`
|
||||||
|
|
||||||
|
Stringifies. In addition to the node argument, it accepts an optional second
|
||||||
|
options object with a single `preferRawType` key. If you don't need to modify
|
||||||
|
JSDoc type AST, you might wish to set this to `true` to get the benefits of
|
||||||
|
preserving the raw form, but for AST-based stringification of JSDoc types,
|
||||||
|
keep it `false` (the default).
|
||||||
|
|
||||||
|
### `jsdocVisitorKeys`
|
||||||
|
|
||||||
|
The [VisitorKeys](https://github.com/eslint/eslint-visitor-keys)
|
||||||
|
for `JsdocBlock`, `JsdocDescriptionLine`, and `JsdocTag`. More likely to be
|
||||||
|
subject to change or dropped in favor of another type parser.
|
||||||
|
|
||||||
|
### `jsdocTypeVisitorKeys`
|
||||||
|
|
||||||
|
Just a re-export of [VisitorKeys](https://github.com/eslint/eslint-visitor-keys)
|
||||||
|
from [`jsdoc-type-pratt-parser`](https://github.com/simonseyock/jsdoc-type-pratt-parser/).
|
||||||
|
|
||||||
|
### `getDefaultTagStructureForMode`
|
||||||
|
|
||||||
|
Provides info on JSDoc tags:
|
||||||
|
|
||||||
|
- `nameContents` ('namepath-referencing'|'namepath-defining'|
|
||||||
|
'dual-namepath-referencing'|false) - Whether and how a name is allowed
|
||||||
|
following any type. Tags without a proper name (value `false`) may still
|
||||||
|
have a description (which can appear like a name); `descriptionAllowed`
|
||||||
|
in such cases would be `true`.
|
||||||
|
The presence of a truthy `nameContents` value is therefore only intended
|
||||||
|
to signify whether separate parsing should occur for a name vs. a
|
||||||
|
description, and what its nature should be.
|
||||||
|
- `nameRequired` (boolean) - Whether a name must be present following any type.
|
||||||
|
- `descriptionAllowed` (boolean) - Whether a description (following any name)
|
||||||
|
is allowed.
|
||||||
|
- `typeAllowed` (boolean) - Whether the tag accepts a curly bracketed portion.
|
||||||
|
Even without a type, a tag may still have a name and/or description.
|
||||||
|
- `typeRequired` (boolean) - Whether a curly bracketed type must be present.
|
||||||
|
- `typeOrNameRequired` (boolean) - Whether either a curly bracketed type is
|
||||||
|
required or a name, but not necessarily both.
|
||||||
|
|
||||||
|
### Miscellaneous
|
||||||
|
|
||||||
|
Also currently exports these utilities:
|
||||||
|
|
||||||
|
- `getTokenizers` - Used with `parseComment` (its main core).
|
||||||
|
- `hasSeeWithLink` - A utility to detect if a tag is `@see` and has a `@link`.
|
||||||
|
- `commentHandler` - Used by `eslint-plugin-jsdoc`.
|
||||||
|
- `commentParserToESTree`- Converts [comment-parser](https://github.com/syavorsky/comment-parser)
|
||||||
|
AST to ESTree/ESLint/Babel friendly AST.
|
||||||
|
- `jsdocVisitorKeys` - The [VisitorKeys](https://github.com/eslint/eslint-visitor-keys)
|
||||||
|
for `JSDocBlock`, `JSDocDescriptionLine`, and `JSDocTag`.
|
||||||
|
- `jsdocTypeVisitorKeys` - [VisitorKeys](https://github.com/eslint/eslint-visitor-keys)
|
||||||
|
for `jsdoc-type-pratt-parser`.
|
||||||
|
- `defaultNoTypes` = The tags which allow no types by default:
|
||||||
|
`default`, `defaultvalue`, `description`, `example`, `file`,
|
||||||
|
`fileoverview`, `license`, `overview`, `see`, `summary`
|
||||||
|
- `defaultNoNames` - The tags which allow no names by default:
|
||||||
|
`access`, `author`, `default`, `defaultvalue`, `description`, `example`,
|
||||||
|
`exception`, `file`, `fileoverview`, `kind`, `license`, `overview`,
|
||||||
|
`return`, `returns`, `since`, `summary`, `throws`, `version`, `variation`
|
||||||
|
|
||||||
|
## ESLint AST produced for `comment-parser` nodes (`JsdocBlock`, `JsdocTag`, and `JsdocDescriptionLine`)
|
||||||
|
|
||||||
|
Note: Although not added in this package, `@es-joy/jsdoc-eslint-parser` adds
|
||||||
|
a `jsdoc` property to other ES nodes (using this project's `getJSDocComment`
|
||||||
|
to determine the specific comment-block that will be attached as AST).
|
||||||
|
|
||||||
|
### `JsdocBlock`
|
||||||
|
|
||||||
|
Has the following visitable properties:
|
||||||
|
|
||||||
|
1. `descriptionLines` (an array of `JsdocDescriptionLine` for multiline
|
||||||
|
descriptions).
|
||||||
|
2. `tags` (an array of `JsdocTag`; see below)
|
||||||
|
3. `inlineTags` (an array of `JsdocInlineTag`; see below)
|
||||||
|
|
||||||
|
Has the following custom non-visitable property:
|
||||||
|
|
||||||
|
1. `delimiterLineBreak` - A string containing any line break after `delimiter`.
|
||||||
|
2. `lastDescriptionLine` - A number
|
||||||
|
3. `endLine` - A number representing the line number with `end`/`terminal`
|
||||||
|
4. `descriptionStartLine` - A 0+ number indicating the line where any
|
||||||
|
description begins
|
||||||
|
5. `descriptionEndLine` - A 0+ number indicating the line where the description
|
||||||
|
ends
|
||||||
|
6. `hasPreterminalDescription` - Set to 0 or 1. On if has a block description
|
||||||
|
on the same line as the terminal `*/`.
|
||||||
|
7. `hasPreterminalTagDescription` - Set to 0 or 1. On if has a tag description
|
||||||
|
on the same line as the terminal `*/`.
|
||||||
|
8. `preterminalLineBreak` - A string containing any line break before `terminal`.
|
||||||
|
|
||||||
|
May also have the following non-visitable properties from `comment-parser`:
|
||||||
|
|
||||||
|
1. `description` - Same as `descriptionLines` but as a string with newlines.
|
||||||
|
2. `delimiter`
|
||||||
|
3. `postDelimiter`
|
||||||
|
4. `lineEnd`
|
||||||
|
5. `initial` (from `start`)
|
||||||
|
6. `terminal` (from `end`)
|
||||||
|
|
||||||
|
### `JsdocTag`
|
||||||
|
|
||||||
|
Has the following visitable properties:
|
||||||
|
|
||||||
|
1. `parsedType` (the `jsdoc-type-pratt-parser` AST representation of the tag's
|
||||||
|
type (see the `jsdoc-type-pratt-parser` section below)).
|
||||||
|
2. `typeLines` (an array of `JsdocTypeLine` for multiline type strings)
|
||||||
|
3. `descriptionLines` (an array of `JsdocDescriptionLine` for multiline
|
||||||
|
descriptions)
|
||||||
|
4. `inlineTags` (an array of `JsdocInlineTag`)
|
||||||
|
|
||||||
|
May also have the following non-visitable properties from `comment-parser`
|
||||||
|
(note that all are included from `comment-parser` except `end` as that is only
|
||||||
|
for JSDoc blocks and note that `type` is renamed to `rawType` and `start` to
|
||||||
|
`initial`):
|
||||||
|
|
||||||
|
1. `description` - Same as `descriptionLines` but as a string with newlines.
|
||||||
|
2. `rawType` - `comment-parser` has this named as `type`, but because of a
|
||||||
|
conflict with ESTree using `type` for Node type, we renamed it to
|
||||||
|
`rawType`. It is otherwise the same as in `comment-parser`, i.e., a string
|
||||||
|
with newlines, though with the initial `{` and final `}` stripped out.
|
||||||
|
See `typeLines` for the array version of this property.
|
||||||
|
3. `initial` - Renamed from `start` to avoid potential conflicts with
|
||||||
|
Acorn-style parser processing tools
|
||||||
|
4. `delimiter`
|
||||||
|
5. `postDelimiter`
|
||||||
|
6. `tag` (this does differ from `comment-parser` now in terms of our stripping
|
||||||
|
the initial `@`)
|
||||||
|
7. `postTag`
|
||||||
|
8. `name`
|
||||||
|
9. `postName`
|
||||||
|
10. `postType`
|
||||||
|
|
||||||
|
### `JsdocDescriptionLine`
|
||||||
|
|
||||||
|
No visitable properties.
|
||||||
|
|
||||||
|
May also have the following non-visitable properties from `comment-parser`:
|
||||||
|
|
||||||
|
1. `delimiter`
|
||||||
|
2. `postDelimiter`
|
||||||
|
3. `initial` (from `start`)
|
||||||
|
4. `description`
|
||||||
|
|
||||||
|
### `JsdocTypeLine`
|
||||||
|
|
||||||
|
No visitable properties.
|
||||||
|
|
||||||
|
May also have the following non-visitable properties from `comment-parser`:
|
||||||
|
|
||||||
|
1. `delimiter`
|
||||||
|
2. `postDelimiter`
|
||||||
|
3. `initial` (from `start`)
|
||||||
|
4. `rawType` - Renamed from `comment-parser` to avoid a conflict. See
|
||||||
|
explanation under `JsdocTag`
|
||||||
|
|
||||||
|
### `JsdocInlineTag`
|
||||||
|
|
||||||
|
No visitable properties.
|
||||||
|
|
||||||
|
Has the following non-visitable properties:
|
||||||
|
|
||||||
|
1. `format`: 'pipe' | 'plain' | 'prefix' | 'space'. These follow the styles of [link](https://jsdoc.app/tags-inline-link.html) or [tutorial](https://jsdoc.app/tags-inline-tutorial.html).
|
||||||
|
1. `pipe`: `{@link namepathOrURL|link text}`
|
||||||
|
2. `plain`: `{@link namepathOrURL}`
|
||||||
|
3. `prefix`: `[link text]{@link namepathOrURL}`
|
||||||
|
4. `space`: `{@link namepathOrURL link text (after the first space)}`
|
||||||
|
2. `namepathOrURL`: string
|
||||||
|
3. `tag`: string. The standard allows `tutorial` or `link`
|
||||||
|
4. `text`: string
|
||||||
|
|
||||||
|
## ESLint AST produced for `jsdoc-type-pratt-parser`
|
||||||
|
|
||||||
|
The AST, including `type`, remains as is from [jsdoc-type-pratt-parser](https://github.com/simonseyock/jsdoc-type-pratt-parser/).
|
||||||
|
|
||||||
|
The type will always begin with a `JsdocType` prefix added, along with a
|
||||||
|
camel-cased type name, e.g., `JsdocTypeUnion`.
|
||||||
|
|
||||||
|
The `jsdoc-type-pratt-parser` visitor keys are also preserved without change.
|
||||||
|
|
||||||
|
You can get a sense of the structure of these types using the parser's
|
||||||
|
[tester](https://jsdoc-type-pratt-parser.github.io/jsdoc-type-pratt-parser/).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm i @es-joy/jsdoccomment
|
||||||
|
```
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
The changelog can be found on the [CHANGES.md](https://github.com/es-joy/jsdoccomment/blob/main/CHANGES.md).
|
||||||
|
<!--## Contributing
|
||||||
|
|
||||||
|
Everyone is welcome to contribute. Please take a moment to review the [contributing guidelines](CONTRIBUTING.md).
|
||||||
|
-->
|
||||||
|
## Authors and license
|
||||||
|
|
||||||
|
[Brett Zamir](http://brett-zamir.me/) and
|
||||||
|
[contributors](https://github.com/es-joy/jsdoccomment/graphs/contributors).
|
||||||
|
|
||||||
|
MIT License, see the included [LICENSE-MIT.txt](https://github.com/es-joy/jsdoccomment/blob/main/LICENSE-MIT.txt) file.
|
||||||
|
|
||||||
|
## To-dos
|
||||||
|
|
||||||
|
1. Get complete code coverage
|
||||||
|
1. Given that `esquery` expects a `right` property to search for `>` (the
|
||||||
|
child selector), we should perhaps insist, for example, that params are
|
||||||
|
the child property for `JsdocBlock` or such. Where `:has()` is currently
|
||||||
|
needed, one could thus instead just use `>`.
|
||||||
|
1. Might add `trailing` for `JsdocBlock` to know whether it is followed by a
|
||||||
|
line break or what not; `comment-parser` does not provide, however
|
||||||
|
1. Fix and properly utilize `indent` argument (challenging for
|
||||||
|
`eslint-plugin-jsdoc` but needed for `jsdoc-eslint-parser` stringifiers
|
||||||
|
to be more faithful); should also then use the proposed `trailing` as well
|
1333
node_modules/@es-joy/jsdoccomment/dist/index.cjs.cjs
generated
vendored
Normal file
1333
node_modules/@es-joy/jsdoccomment/dist/index.cjs.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
361
node_modules/@es-joy/jsdoccomment/dist/index.d.ts
generated
vendored
Normal file
361
node_modules/@es-joy/jsdoccomment/dist/index.d.ts
generated
vendored
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
import * as comment_parser from 'comment-parser';
|
||||||
|
import * as jsdoc_type_pratt_parser from 'jsdoc-type-pratt-parser';
|
||||||
|
export * from 'jsdoc-type-pratt-parser';
|
||||||
|
export { visitorKeys as jsdocTypeVisitorKeys } from 'jsdoc-type-pratt-parser';
|
||||||
|
import * as _typescript_eslint_types from '@typescript-eslint/types';
|
||||||
|
import * as estree from 'estree';
|
||||||
|
import * as eslint from 'eslint';
|
||||||
|
|
||||||
|
type JsdocTypeLine = {
|
||||||
|
delimiter: string;
|
||||||
|
postDelimiter: string;
|
||||||
|
rawType: string;
|
||||||
|
initial: string;
|
||||||
|
type: 'JsdocTypeLine';
|
||||||
|
};
|
||||||
|
type JsdocDescriptionLine = {
|
||||||
|
delimiter: string;
|
||||||
|
description: string;
|
||||||
|
postDelimiter: string;
|
||||||
|
initial: string;
|
||||||
|
type: 'JsdocDescriptionLine';
|
||||||
|
};
|
||||||
|
type JsdocInlineTagNoType = {
|
||||||
|
format: 'pipe' | 'plain' | 'prefix' | 'space';
|
||||||
|
namepathOrURL: string;
|
||||||
|
tag: string;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
type JsdocInlineTag = JsdocInlineTagNoType & {
|
||||||
|
type: 'JsdocInlineTag';
|
||||||
|
};
|
||||||
|
type JsdocTag = {
|
||||||
|
delimiter: string;
|
||||||
|
description: string;
|
||||||
|
descriptionLines: JsdocDescriptionLine[];
|
||||||
|
initial: string;
|
||||||
|
inlineTags: JsdocInlineTag[];
|
||||||
|
name: string;
|
||||||
|
postDelimiter: string;
|
||||||
|
postName: string;
|
||||||
|
postTag: string;
|
||||||
|
postType: string;
|
||||||
|
rawType: string;
|
||||||
|
parsedType: jsdoc_type_pratt_parser.RootResult | null;
|
||||||
|
tag: string;
|
||||||
|
type: 'JsdocTag';
|
||||||
|
typeLines: JsdocTypeLine[];
|
||||||
|
};
|
||||||
|
type Integer = number;
|
||||||
|
type JsdocBlock = {
|
||||||
|
delimiter: string;
|
||||||
|
delimiterLineBreak: string;
|
||||||
|
description: string;
|
||||||
|
descriptionEndLine?: Integer;
|
||||||
|
descriptionLines: JsdocDescriptionLine[];
|
||||||
|
descriptionStartLine?: Integer;
|
||||||
|
hasPreterminalDescription: 0 | 1;
|
||||||
|
hasPreterminalTagDescription?: 1;
|
||||||
|
initial: string;
|
||||||
|
inlineTags: JsdocInlineTag[];
|
||||||
|
lastDescriptionLine?: Integer;
|
||||||
|
endLine: Integer;
|
||||||
|
lineEnd: string;
|
||||||
|
postDelimiter: string;
|
||||||
|
tags: JsdocTag[];
|
||||||
|
terminal: string;
|
||||||
|
preterminalLineBreak: string;
|
||||||
|
type: 'JsdocBlock';
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Converts comment parser AST to ESTree format.
|
||||||
|
* @param {import('.').JsdocBlockWithInline} jsdoc
|
||||||
|
* @param {import('jsdoc-type-pratt-parser').ParseMode} mode
|
||||||
|
* @param {object} opts
|
||||||
|
* @param {'compact'|'preserve'} [opts.spacing] By default, empty lines are
|
||||||
|
* compacted; set to 'preserve' to preserve empty comment lines.
|
||||||
|
* @param {boolean} [opts.throwOnTypeParsingErrors]
|
||||||
|
* @returns {JsdocBlock}
|
||||||
|
*/
|
||||||
|
declare function commentParserToESTree(
|
||||||
|
jsdoc: JsdocBlockWithInline,
|
||||||
|
mode: jsdoc_type_pratt_parser.ParseMode,
|
||||||
|
{
|
||||||
|
spacing,
|
||||||
|
throwOnTypeParsingErrors,
|
||||||
|
}?: {
|
||||||
|
spacing?: 'compact' | 'preserve';
|
||||||
|
throwOnTypeParsingErrors?: boolean;
|
||||||
|
},
|
||||||
|
): JsdocBlock;
|
||||||
|
declare namespace jsdocVisitorKeys {
|
||||||
|
let JsdocBlock: string[];
|
||||||
|
let JsdocDescriptionLine: any[];
|
||||||
|
let JsdocTypeLine: any[];
|
||||||
|
let JsdocTag: string[];
|
||||||
|
let JsdocInlineTag: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{[name: string]: any}} settings
|
||||||
|
* @returns {import('.').CommentHandler}
|
||||||
|
*/
|
||||||
|
declare function commentHandler(settings: { [name: string]: any }): CommentHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo convert for use by escodegen (until may be patched to support
|
||||||
|
* custom entries?).
|
||||||
|
* @param {import('./commentParserToESTree').JsdocBlock|
|
||||||
|
* import('./commentParserToESTree').JsdocDescriptionLine|
|
||||||
|
* import('./commentParserToESTree').JsdocTypeLine|
|
||||||
|
* import('./commentParserToESTree').JsdocTag|
|
||||||
|
* import('./commentParserToESTree').JsdocInlineTag|
|
||||||
|
* import('jsdoc-type-pratt-parser').RootResult
|
||||||
|
* } node
|
||||||
|
* @param {import('.').ESTreeToStringOptions} opts
|
||||||
|
* @throws {Error}
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
declare function estreeToString(
|
||||||
|
node:
|
||||||
|
| JsdocBlock
|
||||||
|
| JsdocDescriptionLine
|
||||||
|
| JsdocTypeLine
|
||||||
|
| JsdocTag
|
||||||
|
| JsdocInlineTag
|
||||||
|
| jsdoc_type_pratt_parser.RootResult,
|
||||||
|
opts?: ESTreeToStringOptions,
|
||||||
|
): string;
|
||||||
|
|
||||||
|
type Token =
|
||||||
|
| eslint.AST.Token
|
||||||
|
| estree.Comment
|
||||||
|
| {
|
||||||
|
type: eslint.AST.TokenType | 'Line' | 'Block' | 'Shebang';
|
||||||
|
range: [number, number];
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
type ESLintOrTSNode = eslint.Rule.Node | _typescript_eslint_types.TSESTree.Node;
|
||||||
|
type int = number;
|
||||||
|
/**
|
||||||
|
* Reduces the provided node to the appropriate node for evaluating
|
||||||
|
* JSDoc comment status.
|
||||||
|
*
|
||||||
|
* @param {ESLintOrTSNode} node An AST node.
|
||||||
|
* @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode.
|
||||||
|
* @returns {ESLintOrTSNode} The AST node that
|
||||||
|
* can be evaluated for appropriate JSDoc comments.
|
||||||
|
*/
|
||||||
|
declare function getReducedASTNode(node: ESLintOrTSNode, sourceCode: eslint.SourceCode): ESLintOrTSNode;
|
||||||
|
/**
|
||||||
|
* Retrieves the JSDoc comment for a given node.
|
||||||
|
*
|
||||||
|
* @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode
|
||||||
|
* @param {import('eslint').Rule.Node} node The AST node to get
|
||||||
|
* the comment for.
|
||||||
|
* @param {{maxLines: int, minLines: int, [name: string]: any}} settings The
|
||||||
|
* settings in context
|
||||||
|
* @returns {Token|null} The Block comment
|
||||||
|
* token containing the JSDoc comment for the given node or
|
||||||
|
* null if not found.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
declare function getJSDocComment(
|
||||||
|
sourceCode: eslint.SourceCode,
|
||||||
|
node: eslint.Rule.Node,
|
||||||
|
settings: {
|
||||||
|
maxLines: int;
|
||||||
|
minLines: int;
|
||||||
|
[name: string]: any;
|
||||||
|
},
|
||||||
|
): Token | null;
|
||||||
|
/**
|
||||||
|
* Retrieves the comment preceding a given node.
|
||||||
|
*
|
||||||
|
* @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode
|
||||||
|
* @param {ESLintOrTSNode} node The AST node to get
|
||||||
|
* the comment for.
|
||||||
|
* @param {{maxLines: int, minLines: int, [name: string]: any}} settings The
|
||||||
|
* settings in context
|
||||||
|
* @returns {Token|null} The Block comment
|
||||||
|
* token containing the JSDoc comment for the given node or
|
||||||
|
* null if not found.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
declare function getNonJsdocComment(
|
||||||
|
sourceCode: eslint.SourceCode,
|
||||||
|
node: ESLintOrTSNode,
|
||||||
|
settings: {
|
||||||
|
maxLines: int;
|
||||||
|
minLines: int;
|
||||||
|
[name: string]: any;
|
||||||
|
},
|
||||||
|
): Token | null;
|
||||||
|
/**
|
||||||
|
* @param {(ESLintOrTSNode|import('estree').Comment) & {
|
||||||
|
* declaration?: any,
|
||||||
|
* decorators?: any[],
|
||||||
|
* parent?: import('eslint').Rule.Node & {
|
||||||
|
* decorators?: any[]
|
||||||
|
* }
|
||||||
|
* }} node
|
||||||
|
* @returns {import('@typescript-eslint/types').TSESTree.Decorator|undefined}
|
||||||
|
*/
|
||||||
|
declare function getDecorator(
|
||||||
|
node: (ESLintOrTSNode | estree.Comment) & {
|
||||||
|
declaration?: any;
|
||||||
|
decorators?: any[];
|
||||||
|
parent?: eslint.Rule.Node & {
|
||||||
|
decorators?: any[];
|
||||||
|
};
|
||||||
|
},
|
||||||
|
): _typescript_eslint_types.TSESTree.Decorator | undefined;
|
||||||
|
/**
|
||||||
|
* Checks for the presence of a JSDoc comment for the given node and returns it.
|
||||||
|
*
|
||||||
|
* @param {ESLintOrTSNode} astNode The AST node to get
|
||||||
|
* the comment for.
|
||||||
|
* @param {import('eslint').SourceCode} sourceCode
|
||||||
|
* @param {{maxLines: int, minLines: int, [name: string]: any}} settings
|
||||||
|
* @param {{nonJSDoc?: boolean}} [opts]
|
||||||
|
* @returns {Token|null} The Block comment token containing the JSDoc comment
|
||||||
|
* for the given node or null if not found.
|
||||||
|
*/
|
||||||
|
declare function findJSDocComment(
|
||||||
|
astNode: ESLintOrTSNode,
|
||||||
|
sourceCode: eslint.SourceCode,
|
||||||
|
settings: {
|
||||||
|
maxLines: int;
|
||||||
|
minLines: int;
|
||||||
|
[name: string]: any;
|
||||||
|
},
|
||||||
|
opts?: {
|
||||||
|
nonJSDoc?: boolean;
|
||||||
|
},
|
||||||
|
): Token | null;
|
||||||
|
/**
|
||||||
|
* Checks for the presence of a comment following the given node and
|
||||||
|
* returns it.
|
||||||
|
*
|
||||||
|
* This method is experimental.
|
||||||
|
*
|
||||||
|
* @param {import('eslint').SourceCode} sourceCode
|
||||||
|
* @param {ESLintOrTSNode} astNode The AST node to get
|
||||||
|
* the comment for.
|
||||||
|
* @returns {Token|null} The comment token containing the comment
|
||||||
|
* for the given node or null if not found.
|
||||||
|
*/
|
||||||
|
declare function getFollowingComment(sourceCode: eslint.SourceCode, astNode: ESLintOrTSNode): Token | null;
|
||||||
|
|
||||||
|
declare function hasSeeWithLink(spec: comment_parser.Spec): boolean;
|
||||||
|
declare const defaultNoTypes: string[];
|
||||||
|
declare const defaultNoNames: string[];
|
||||||
|
/**
|
||||||
|
* Can't import `comment-parser/es6/parser/tokenizers/index.js`,
|
||||||
|
* so we redefine here.
|
||||||
|
*/
|
||||||
|
type CommentParserTokenizer = (spec: comment_parser.Spec) => comment_parser.Spec;
|
||||||
|
/**
|
||||||
|
* Can't import `comment-parser/es6/parser/tokenizers/index.js`,
|
||||||
|
* so we redefine here.
|
||||||
|
* @typedef {(spec: import('comment-parser').Spec) =>
|
||||||
|
* import('comment-parser').Spec} CommentParserTokenizer
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @param {object} [cfg]
|
||||||
|
* @param {string[]} [cfg.noTypes]
|
||||||
|
* @param {string[]} [cfg.noNames]
|
||||||
|
* @returns {CommentParserTokenizer[]}
|
||||||
|
*/
|
||||||
|
declare function getTokenizers({
|
||||||
|
noTypes,
|
||||||
|
noNames,
|
||||||
|
}?: {
|
||||||
|
noTypes?: string[];
|
||||||
|
noNames?: string[];
|
||||||
|
}): CommentParserTokenizer[];
|
||||||
|
/**
|
||||||
|
* Accepts a comment token or complete comment string and converts it into
|
||||||
|
* `comment-parser` AST.
|
||||||
|
* @param {string | {value: string}} commentOrNode
|
||||||
|
* @param {string} [indent] Whitespace
|
||||||
|
* @returns {import('.').JsdocBlockWithInline}
|
||||||
|
*/
|
||||||
|
declare function parseComment(
|
||||||
|
commentOrNode:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
value: string;
|
||||||
|
},
|
||||||
|
indent?: string,
|
||||||
|
): JsdocBlockWithInline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits the `{@prefix}` from remaining `Spec.lines[].token.description`
|
||||||
|
* into the `inlineTags` tokens, and populates `spec.inlineTags`
|
||||||
|
* @param {import('comment-parser').Block} block
|
||||||
|
* @returns {import('.').JsdocBlockWithInline}
|
||||||
|
*/
|
||||||
|
declare function parseInlineTags(block: comment_parser.Block): JsdocBlockWithInline;
|
||||||
|
|
||||||
|
type InlineTag = JsdocInlineTagNoType & {
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
};
|
||||||
|
type JsdocTagWithInline = comment_parser.Spec & {
|
||||||
|
line?: Integer;
|
||||||
|
inlineTags: (JsdocInlineTagNoType & {
|
||||||
|
line?: Integer;
|
||||||
|
})[];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Expands on comment-parser's `Block` interface.
|
||||||
|
*/
|
||||||
|
type JsdocBlockWithInline = {
|
||||||
|
description: string;
|
||||||
|
source: comment_parser.Line[];
|
||||||
|
problems: comment_parser.Problem[];
|
||||||
|
tags: JsdocTagWithInline[];
|
||||||
|
inlineTags: (JsdocInlineTagNoType & {
|
||||||
|
line?: Integer;
|
||||||
|
})[];
|
||||||
|
};
|
||||||
|
type ESTreeToStringOptions = {
|
||||||
|
preferRawType?: boolean;
|
||||||
|
};
|
||||||
|
type CommentHandler = (commentSelector: string, jsdoc: JsdocBlockWithInline) => boolean;
|
||||||
|
|
||||||
|
export {
|
||||||
|
type CommentHandler,
|
||||||
|
type CommentParserTokenizer,
|
||||||
|
type ESLintOrTSNode,
|
||||||
|
type ESTreeToStringOptions,
|
||||||
|
type InlineTag,
|
||||||
|
type Integer,
|
||||||
|
JsdocBlock,
|
||||||
|
type JsdocBlockWithInline,
|
||||||
|
JsdocDescriptionLine,
|
||||||
|
JsdocInlineTag,
|
||||||
|
type JsdocInlineTagNoType,
|
||||||
|
JsdocTag,
|
||||||
|
type JsdocTagWithInline,
|
||||||
|
JsdocTypeLine,
|
||||||
|
type Token,
|
||||||
|
commentHandler,
|
||||||
|
commentParserToESTree,
|
||||||
|
defaultNoNames,
|
||||||
|
defaultNoTypes,
|
||||||
|
estreeToString,
|
||||||
|
findJSDocComment,
|
||||||
|
getDecorator,
|
||||||
|
getFollowingComment,
|
||||||
|
getJSDocComment,
|
||||||
|
getNonJsdocComment,
|
||||||
|
getReducedASTNode,
|
||||||
|
getTokenizers,
|
||||||
|
hasSeeWithLink,
|
||||||
|
type int,
|
||||||
|
jsdocVisitorKeys,
|
||||||
|
parseComment,
|
||||||
|
parseInlineTags,
|
||||||
|
};
|
106
node_modules/@es-joy/jsdoccomment/package.json
generated
vendored
Normal file
106
node_modules/@es-joy/jsdoccomment/package.json
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
{
|
||||||
|
"name": "@es-joy/jsdoccomment",
|
||||||
|
"version": "0.46.0",
|
||||||
|
"author": "Brett Zamir <brettz9@yahoo.com>",
|
||||||
|
"contributors": [],
|
||||||
|
"description": "Maintained replacement for ESLint's deprecated SourceCode#getJSDocComment along with other jsdoc utilities",
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"ast",
|
||||||
|
"comment",
|
||||||
|
"estree",
|
||||||
|
"jsdoc",
|
||||||
|
"parser",
|
||||||
|
"eslint",
|
||||||
|
"sourcecode"
|
||||||
|
],
|
||||||
|
"type": "module",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./src/index.js",
|
||||||
|
"require": "./dist/index.cjs.cjs"
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"cover 100%"
|
||||||
|
],
|
||||||
|
"typedocOptions": {
|
||||||
|
"dmtLinksService": {
|
||||||
|
"GitHub": "https://github.com/es-joy/jsdoccomment",
|
||||||
|
"NPM": "https://www.npmjs.com/package/@es-joy/jsdoccomment"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/es-joy/jsdoccomment.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/es-joy/jsdoccomment/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/es-joy/jsdoccomment",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"comment-parser": "1.4.1",
|
||||||
|
"esquery": "^1.6.0",
|
||||||
|
"jsdoc-type-pratt-parser": "~4.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.24.7",
|
||||||
|
"@babel/plugin-syntax-class-properties": "^7.12.13",
|
||||||
|
"@babel/preset-env": "^7.24.7",
|
||||||
|
"@brettz9/eslint-plugin": "^1.0.4",
|
||||||
|
"@rollup/plugin-babel": "^6.0.4",
|
||||||
|
"@types/eslint": "^8.56.10",
|
||||||
|
"@types/esquery": "^1.5.4",
|
||||||
|
"@types/estraverse": "^5.1.7",
|
||||||
|
"@types/estree": "^1.0.5",
|
||||||
|
"@typescript-eslint/types": "^7.16.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "^7.16.0",
|
||||||
|
"@typhonjs-build-test/esm-d-ts": "0.3.0-next.1",
|
||||||
|
"@typhonjs-typedoc/typedoc-pkg": "^0.0.5",
|
||||||
|
"@vitest/coverage-v8": "^2.0.1",
|
||||||
|
"@vitest/ui": "^2.0.1",
|
||||||
|
"eslint": "^8.56.0",
|
||||||
|
"eslint-config-ash-nazg": "35.3.0",
|
||||||
|
"eslint-config-standard": "^17.1.0",
|
||||||
|
"eslint-plugin-array-func": "^4.0.0",
|
||||||
|
"eslint-plugin-compat": "^4.2.0",
|
||||||
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||||
|
"eslint-plugin-html": "^7.1.0",
|
||||||
|
"eslint-plugin-import": "^2.29.1",
|
||||||
|
"eslint-plugin-jsdoc": "^48.0.4",
|
||||||
|
"eslint-plugin-markdown": "^3.0.1",
|
||||||
|
"eslint-plugin-n": "^16.6.2",
|
||||||
|
"eslint-plugin-no-unsanitized": "^4.0.2",
|
||||||
|
"eslint-plugin-no-use-extend-native": "^0.5.0",
|
||||||
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
|
"eslint-plugin-sonarjs": "^0.23.0",
|
||||||
|
"eslint-plugin-unicorn": "^50.0.1",
|
||||||
|
"espree": "^10.1.0",
|
||||||
|
"estraverse": "^5.3.0",
|
||||||
|
"rollup": "^4.18.1",
|
||||||
|
"typescript": "^5.5.3",
|
||||||
|
"typescript-eslint": "^7.16.0",
|
||||||
|
"vitest": "^2.0.1"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"/dist",
|
||||||
|
"/src",
|
||||||
|
"CHANGES.md",
|
||||||
|
"LICENSE-MIT.txt"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "rollup -c && npm run types",
|
||||||
|
"docs": "typedoc-pkg --api-link es",
|
||||||
|
"eslint": "eslint --ext=js,cjs,md,html .",
|
||||||
|
"lint": "npm run eslint --",
|
||||||
|
"open": "open ./coverage/index.html",
|
||||||
|
"test": "npm run lint && npm run build && npm run test-ui",
|
||||||
|
"test-ui": "vitest --ui --coverage",
|
||||||
|
"test-cov": "vitest --coverage",
|
||||||
|
"tsc": "tsc",
|
||||||
|
"types": "esm-d-ts gen ./src/index.js --output ./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
}
|
39
node_modules/@es-joy/jsdoccomment/src/commentHandler.js
generated
vendored
Normal file
39
node_modules/@es-joy/jsdoccomment/src/commentHandler.js
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import esquery from 'esquery';
|
||||||
|
|
||||||
|
import {
|
||||||
|
visitorKeys as jsdocTypePrattParserVisitorKeys
|
||||||
|
} from 'jsdoc-type-pratt-parser';
|
||||||
|
|
||||||
|
import {
|
||||||
|
commentParserToESTree, jsdocVisitorKeys
|
||||||
|
} from './commentParserToESTree.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{[name: string]: any}} settings
|
||||||
|
* @returns {import('.').CommentHandler}
|
||||||
|
*/
|
||||||
|
const commentHandler = (settings) => {
|
||||||
|
/**
|
||||||
|
* @type {import('.').CommentHandler}
|
||||||
|
*/
|
||||||
|
return (commentSelector, jsdoc) => {
|
||||||
|
const {mode} = settings;
|
||||||
|
|
||||||
|
const selector = esquery.parse(commentSelector);
|
||||||
|
|
||||||
|
const ast = commentParserToESTree(jsdoc, mode);
|
||||||
|
|
||||||
|
const _ast = /** @type {unknown} */ (ast);
|
||||||
|
|
||||||
|
return esquery.matches(/** @type {import('estree').Node} */ (
|
||||||
|
_ast
|
||||||
|
), selector, undefined, {
|
||||||
|
visitorKeys: {
|
||||||
|
...jsdocTypePrattParserVisitorKeys,
|
||||||
|
...jsdocVisitorKeys
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export {commentHandler};
|
504
node_modules/@es-joy/jsdoccomment/src/commentParserToESTree.js
generated
vendored
Normal file
504
node_modules/@es-joy/jsdoccomment/src/commentParserToESTree.js
generated
vendored
Normal file
@ -0,0 +1,504 @@
|
|||||||
|
import {parse as jsdocTypePrattParse} from 'jsdoc-type-pratt-parser';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes initial and ending brackets from `rawType`
|
||||||
|
* @param {JsdocTypeLine[]|JsdocTag} container
|
||||||
|
* @param {boolean} [isArr]
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
const stripEncapsulatingBrackets = (container, isArr) => {
|
||||||
|
if (isArr) {
|
||||||
|
const firstItem = /** @type {JsdocTypeLine[]} */ (container)[0];
|
||||||
|
firstItem.rawType = firstItem.rawType.replace(
|
||||||
|
/^\{/u, ''
|
||||||
|
);
|
||||||
|
|
||||||
|
const lastItem = /** @type {JsdocTypeLine} */ (
|
||||||
|
/** @type {JsdocTypeLine[]} */ (
|
||||||
|
container
|
||||||
|
).at(-1)
|
||||||
|
);
|
||||||
|
lastItem.rawType = lastItem.rawType.replace(/\}$/u, '');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/** @type {JsdocTag} */ (container).rawType =
|
||||||
|
/** @type {JsdocTag} */ (container).rawType.replace(
|
||||||
|
/^\{/u, ''
|
||||||
|
).replace(/\}$/u, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* delimiter: string,
|
||||||
|
* postDelimiter: string,
|
||||||
|
* rawType: string,
|
||||||
|
* initial: string,
|
||||||
|
* type: "JsdocTypeLine"
|
||||||
|
* }} JsdocTypeLine
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* delimiter: string,
|
||||||
|
* description: string,
|
||||||
|
* postDelimiter: string,
|
||||||
|
* initial: string,
|
||||||
|
* type: "JsdocDescriptionLine"
|
||||||
|
* }} JsdocDescriptionLine
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* format: 'pipe' | 'plain' | 'prefix' | 'space',
|
||||||
|
* namepathOrURL: string,
|
||||||
|
* tag: string,
|
||||||
|
* text: string,
|
||||||
|
* }} JsdocInlineTagNoType
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @typedef {JsdocInlineTagNoType & {
|
||||||
|
* type: "JsdocInlineTag"
|
||||||
|
* }} JsdocInlineTag
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* delimiter: string,
|
||||||
|
* description: string,
|
||||||
|
* descriptionLines: JsdocDescriptionLine[],
|
||||||
|
* initial: string,
|
||||||
|
* inlineTags: JsdocInlineTag[]
|
||||||
|
* name: string,
|
||||||
|
* postDelimiter: string,
|
||||||
|
* postName: string,
|
||||||
|
* postTag: string,
|
||||||
|
* postType: string,
|
||||||
|
* rawType: string,
|
||||||
|
* parsedType: import('jsdoc-type-pratt-parser').RootResult|null
|
||||||
|
* tag: string,
|
||||||
|
* type: "JsdocTag",
|
||||||
|
* typeLines: JsdocTypeLine[],
|
||||||
|
* }} JsdocTag
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {number} Integer
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* delimiter: string,
|
||||||
|
* delimiterLineBreak: string,
|
||||||
|
* description: string,
|
||||||
|
* descriptionEndLine?: Integer,
|
||||||
|
* descriptionLines: JsdocDescriptionLine[],
|
||||||
|
* descriptionStartLine?: Integer,
|
||||||
|
* hasPreterminalDescription: 0|1,
|
||||||
|
* hasPreterminalTagDescription?: 1,
|
||||||
|
* initial: string,
|
||||||
|
* inlineTags: JsdocInlineTag[]
|
||||||
|
* lastDescriptionLine?: Integer,
|
||||||
|
* endLine: Integer,
|
||||||
|
* lineEnd: string,
|
||||||
|
* postDelimiter: string,
|
||||||
|
* tags: JsdocTag[],
|
||||||
|
* terminal: string,
|
||||||
|
* preterminalLineBreak: string,
|
||||||
|
* type: "JsdocBlock",
|
||||||
|
* }} JsdocBlock
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} cfg
|
||||||
|
* @param {string} cfg.text
|
||||||
|
* @param {string} cfg.tag
|
||||||
|
* @param {'pipe' | 'plain' | 'prefix' | 'space'} cfg.format
|
||||||
|
* @param {string} cfg.namepathOrURL
|
||||||
|
* @returns {JsdocInlineTag}
|
||||||
|
*/
|
||||||
|
const inlineTagToAST = ({text, tag, format, namepathOrURL}) => ({
|
||||||
|
text,
|
||||||
|
tag,
|
||||||
|
format,
|
||||||
|
namepathOrURL,
|
||||||
|
type: 'JsdocInlineTag'
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts comment parser AST to ESTree format.
|
||||||
|
* @param {import('.').JsdocBlockWithInline} jsdoc
|
||||||
|
* @param {import('jsdoc-type-pratt-parser').ParseMode} mode
|
||||||
|
* @param {object} opts
|
||||||
|
* @param {'compact'|'preserve'} [opts.spacing] By default, empty lines are
|
||||||
|
* compacted; set to 'preserve' to preserve empty comment lines.
|
||||||
|
* @param {boolean} [opts.throwOnTypeParsingErrors]
|
||||||
|
* @returns {JsdocBlock}
|
||||||
|
*/
|
||||||
|
const commentParserToESTree = (jsdoc, mode, {
|
||||||
|
spacing = 'compact',
|
||||||
|
throwOnTypeParsingErrors = false
|
||||||
|
} = {}) => {
|
||||||
|
/**
|
||||||
|
* Strips brackets from a tag's `rawType` values and adds `parsedType`
|
||||||
|
* @param {JsdocTag} lastTag
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
const cleanUpLastTag = (lastTag) => {
|
||||||
|
// Strip out `}` that encapsulates and is not part of
|
||||||
|
// the type
|
||||||
|
stripEncapsulatingBrackets(lastTag);
|
||||||
|
|
||||||
|
if (lastTag.typeLines.length) {
|
||||||
|
stripEncapsulatingBrackets(lastTag.typeLines, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove single empty line description.
|
||||||
|
if (lastTag.descriptionLines.length === 1 &&
|
||||||
|
lastTag.descriptionLines[0].description === '') {
|
||||||
|
lastTag.descriptionLines.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// With even a multiline type now in full, add parsing
|
||||||
|
let parsedType = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
parsedType = jsdocTypePrattParse(lastTag.rawType, mode);
|
||||||
|
} catch (err) {
|
||||||
|
// Ignore
|
||||||
|
if (lastTag.rawType && throwOnTypeParsingErrors) {
|
||||||
|
/** @type {Error} */ (
|
||||||
|
err
|
||||||
|
).message = `Tag @${lastTag.tag} with raw type ` +
|
||||||
|
`\`${lastTag.rawType}\` had parsing error: ${
|
||||||
|
/** @type {Error} */ (err).message}`;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastTag.parsedType = parsedType;
|
||||||
|
};
|
||||||
|
|
||||||
|
const {source, inlineTags: blockInlineTags} = jsdoc;
|
||||||
|
|
||||||
|
const {tokens: {
|
||||||
|
delimiter: delimiterRoot,
|
||||||
|
lineEnd: lineEndRoot,
|
||||||
|
postDelimiter: postDelimiterRoot,
|
||||||
|
start: startRoot,
|
||||||
|
end: endRoot
|
||||||
|
}} = source[0];
|
||||||
|
|
||||||
|
const endLine = source.length - 1;
|
||||||
|
|
||||||
|
/** @type {JsdocBlock} */
|
||||||
|
const ast = {
|
||||||
|
delimiter: delimiterRoot,
|
||||||
|
delimiterLineBreak: '\n',
|
||||||
|
description: '',
|
||||||
|
|
||||||
|
descriptionLines: [],
|
||||||
|
inlineTags: blockInlineTags.map((t) => inlineTagToAST(t)),
|
||||||
|
|
||||||
|
initial: startRoot,
|
||||||
|
tags: [],
|
||||||
|
// `terminal` will be overwritten if there are other entries
|
||||||
|
terminal: endRoot,
|
||||||
|
preterminalLineBreak: '\n',
|
||||||
|
hasPreterminalDescription: 0,
|
||||||
|
endLine,
|
||||||
|
postDelimiter: postDelimiterRoot,
|
||||||
|
lineEnd: lineEndRoot,
|
||||||
|
|
||||||
|
type: 'JsdocBlock'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {JsdocTag[]}
|
||||||
|
*/
|
||||||
|
const tags = [];
|
||||||
|
|
||||||
|
/** @type {Integer|undefined} */
|
||||||
|
let lastDescriptionLine;
|
||||||
|
|
||||||
|
/** @type {JsdocTag|null} */
|
||||||
|
let lastTag = null;
|
||||||
|
|
||||||
|
// Tracks when first valid tag description line is seen.
|
||||||
|
let tagDescriptionSeen = false;
|
||||||
|
|
||||||
|
let descLineStateOpen = true;
|
||||||
|
|
||||||
|
source.forEach((info, idx) => {
|
||||||
|
const {tokens} = info;
|
||||||
|
const {
|
||||||
|
delimiter,
|
||||||
|
description,
|
||||||
|
postDelimiter,
|
||||||
|
start: initial,
|
||||||
|
tag,
|
||||||
|
end,
|
||||||
|
type: rawType
|
||||||
|
} = tokens;
|
||||||
|
|
||||||
|
if (!tag && description && descLineStateOpen) {
|
||||||
|
if (ast.descriptionStartLine === undefined) {
|
||||||
|
ast.descriptionStartLine = idx;
|
||||||
|
}
|
||||||
|
ast.descriptionEndLine = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag || end) {
|
||||||
|
descLineStateOpen = false;
|
||||||
|
if (lastDescriptionLine === undefined) {
|
||||||
|
lastDescriptionLine = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean-up with last tag before end or new tag
|
||||||
|
if (lastTag) {
|
||||||
|
cleanUpLastTag(lastTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the iteration when we reach the end
|
||||||
|
// but only when there is no tag earlier in the line
|
||||||
|
// to still process
|
||||||
|
if (end && !tag) {
|
||||||
|
ast.terminal = end;
|
||||||
|
|
||||||
|
// Check if there are any description lines and if not then this is a
|
||||||
|
// one line comment block.
|
||||||
|
const isDelimiterLine = ast.descriptionLines.length === 0 &&
|
||||||
|
delimiter === '/**';
|
||||||
|
|
||||||
|
// Remove delimiter line break for one line comments blocks.
|
||||||
|
if (isDelimiterLine) {
|
||||||
|
ast.delimiterLineBreak = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (description) {
|
||||||
|
// Remove terminal line break at end when description is defined.
|
||||||
|
if (ast.terminal === '*/') {
|
||||||
|
ast.preterminalLineBreak = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastTag) {
|
||||||
|
ast.hasPreterminalTagDescription = 1;
|
||||||
|
} else {
|
||||||
|
ast.hasPreterminalDescription = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const holder = lastTag || ast;
|
||||||
|
holder.description += (holder.description ? '\n' : '') + description;
|
||||||
|
|
||||||
|
// Do not include `delimiter` / `postDelimiter` for opening
|
||||||
|
// delimiter line.
|
||||||
|
|
||||||
|
holder.descriptionLines.push({
|
||||||
|
delimiter: isDelimiterLine ? '' : delimiter,
|
||||||
|
description,
|
||||||
|
postDelimiter: isDelimiterLine ? '' : postDelimiter,
|
||||||
|
initial,
|
||||||
|
type: 'JsdocDescriptionLine'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
// eslint-disable-next-line no-unused-vars -- Discarding
|
||||||
|
end: ed,
|
||||||
|
delimiter: de,
|
||||||
|
postDelimiter: pd,
|
||||||
|
start: init,
|
||||||
|
...tkns
|
||||||
|
} = tokens;
|
||||||
|
|
||||||
|
if (!tokens.name) {
|
||||||
|
let i = 1;
|
||||||
|
while (source[idx + i]) {
|
||||||
|
const {tokens: {
|
||||||
|
name,
|
||||||
|
postName,
|
||||||
|
postType,
|
||||||
|
tag: tg
|
||||||
|
}} = source[idx + i];
|
||||||
|
if (tg) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (name) {
|
||||||
|
tkns.postType = postType;
|
||||||
|
tkns.name = name;
|
||||||
|
tkns.postName = postName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {JsdocInlineTag[]}
|
||||||
|
*/
|
||||||
|
let tagInlineTags = [];
|
||||||
|
if (tag) {
|
||||||
|
// Assuming the tags from `source` are in the same order as `jsdoc.tags`
|
||||||
|
// we can use the `tags` length as index into the parser result tags.
|
||||||
|
tagInlineTags =
|
||||||
|
/**
|
||||||
|
* @type {import('comment-parser').Spec & {
|
||||||
|
* inlineTags: JsdocInlineTagNoType[]
|
||||||
|
* }}
|
||||||
|
*/ (
|
||||||
|
jsdoc.tags[tags.length]
|
||||||
|
).inlineTags.map(
|
||||||
|
(t) => inlineTagToAST(t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {JsdocTag} */
|
||||||
|
const tagObj = {
|
||||||
|
...tkns,
|
||||||
|
initial: endLine ? init : '',
|
||||||
|
postDelimiter: lastDescriptionLine ? pd : '',
|
||||||
|
delimiter: lastDescriptionLine ? de : '',
|
||||||
|
descriptionLines: [],
|
||||||
|
inlineTags: tagInlineTags,
|
||||||
|
parsedType: null,
|
||||||
|
rawType: '',
|
||||||
|
type: 'JsdocTag',
|
||||||
|
typeLines: []
|
||||||
|
};
|
||||||
|
tagObj.tag = tagObj.tag.replace(/^@/u, '');
|
||||||
|
|
||||||
|
lastTag = tagObj;
|
||||||
|
tagDescriptionSeen = false;
|
||||||
|
|
||||||
|
tags.push(tagObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawType) {
|
||||||
|
// Will strip rawType brackets after this tag
|
||||||
|
/** @type {JsdocTag} */ (lastTag).typeLines.push(
|
||||||
|
/** @type {JsdocTag} */ (lastTag).typeLines.length
|
||||||
|
? {
|
||||||
|
delimiter,
|
||||||
|
postDelimiter,
|
||||||
|
rawType,
|
||||||
|
initial,
|
||||||
|
type: 'JsdocTypeLine'
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
delimiter: '',
|
||||||
|
postDelimiter: '',
|
||||||
|
rawType,
|
||||||
|
initial: '',
|
||||||
|
type: 'JsdocTypeLine'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
/** @type {JsdocTag} */ (lastTag).rawType += /** @type {JsdocTag} */ (
|
||||||
|
lastTag
|
||||||
|
).rawType
|
||||||
|
? '\n' + rawType
|
||||||
|
: rawType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In `compact` mode skip processing if `description` is an empty string
|
||||||
|
// unless lastTag is being processed.
|
||||||
|
//
|
||||||
|
// In `preserve` mode process when `description` is not the `empty string
|
||||||
|
// or the `delimiter` is not `/**` ensuring empty lines are preserved.
|
||||||
|
if (((spacing === 'compact' && description) || lastTag) ||
|
||||||
|
(spacing === 'preserve' && (description || delimiter !== '/**'))) {
|
||||||
|
const holder = lastTag || ast;
|
||||||
|
|
||||||
|
// Check if there are any description lines and if not then this is a
|
||||||
|
// multi-line comment block with description on 0th line. Treat
|
||||||
|
// `delimiter` / `postDelimiter` / `initial` as being on a new line.
|
||||||
|
const isDelimiterLine = holder.descriptionLines.length === 0 &&
|
||||||
|
delimiter === '/**';
|
||||||
|
|
||||||
|
// Remove delimiter line break for one line comments blocks.
|
||||||
|
if (isDelimiterLine) {
|
||||||
|
ast.delimiterLineBreak = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track when the first description line is seen to avoid adding empty
|
||||||
|
// description lines for tag type lines.
|
||||||
|
tagDescriptionSeen ||= Boolean(lastTag &&
|
||||||
|
(rawType === '' || rawType?.endsWith('}')));
|
||||||
|
|
||||||
|
if (lastTag) {
|
||||||
|
if (tagDescriptionSeen) {
|
||||||
|
// The first tag description line is a continuation after type /
|
||||||
|
// name parsing.
|
||||||
|
const isFirstDescriptionLine = holder.descriptionLines.length === 0;
|
||||||
|
|
||||||
|
// For `compact` spacing must allow through first description line.
|
||||||
|
if ((spacing === 'compact' &&
|
||||||
|
(description || isFirstDescriptionLine)) ||
|
||||||
|
spacing === 'preserve') {
|
||||||
|
holder.descriptionLines.push({
|
||||||
|
delimiter: isFirstDescriptionLine ? '' : delimiter,
|
||||||
|
description,
|
||||||
|
postDelimiter: isFirstDescriptionLine ? '' : postDelimiter,
|
||||||
|
initial: isFirstDescriptionLine ? '' : initial,
|
||||||
|
type: 'JsdocDescriptionLine'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
holder.descriptionLines.push({
|
||||||
|
delimiter: isDelimiterLine ? '' : delimiter,
|
||||||
|
description,
|
||||||
|
postDelimiter: isDelimiterLine ? '' : postDelimiter,
|
||||||
|
initial: isDelimiterLine ? `` : initial,
|
||||||
|
type: 'JsdocDescriptionLine'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tag) {
|
||||||
|
if (lastTag) {
|
||||||
|
// For `compact` spacing must filter out any empty description lines
|
||||||
|
// after the initial `holder.description` has content.
|
||||||
|
if (tagDescriptionSeen && !(spacing === 'compact' &&
|
||||||
|
holder.description && description === '')) {
|
||||||
|
holder.description += !holder.description
|
||||||
|
? description
|
||||||
|
: '\n' + description;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
holder.description += !holder.description
|
||||||
|
? description
|
||||||
|
: '\n' + description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean-up where last line itself has tag content
|
||||||
|
if (end && tag) {
|
||||||
|
ast.terminal = end;
|
||||||
|
ast.hasPreterminalTagDescription = 1;
|
||||||
|
|
||||||
|
// Remove terminal line break at end when tag is defined on last line.
|
||||||
|
if (ast.terminal === '*/') {
|
||||||
|
ast.preterminalLineBreak = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanUpLastTag(/** @type {JsdocTag} */ (lastTag));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ast.lastDescriptionLine = lastDescriptionLine;
|
||||||
|
ast.tags = tags;
|
||||||
|
|
||||||
|
return ast;
|
||||||
|
};
|
||||||
|
|
||||||
|
const jsdocVisitorKeys = {
|
||||||
|
JsdocBlock: ['descriptionLines', 'tags', 'inlineTags'],
|
||||||
|
JsdocDescriptionLine: [],
|
||||||
|
JsdocTypeLine: [],
|
||||||
|
JsdocTag: ['parsedType', 'typeLines', 'descriptionLines', 'inlineTags'],
|
||||||
|
JsdocInlineTag: []
|
||||||
|
};
|
||||||
|
|
||||||
|
export {commentParserToESTree, jsdocVisitorKeys};
|
179
node_modules/@es-joy/jsdoccomment/src/estreeToString.js
generated
vendored
Normal file
179
node_modules/@es-joy/jsdoccomment/src/estreeToString.js
generated
vendored
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
import {stringify as prattStringify} from 'jsdoc-type-pratt-parser';
|
||||||
|
|
||||||
|
/** @type {Record<string, Function>} */
|
||||||
|
const stringifiers = {
|
||||||
|
JsdocBlock,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./commentParserToESTree').JsdocDescriptionLine} node
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
JsdocDescriptionLine ({
|
||||||
|
initial, delimiter, postDelimiter, description
|
||||||
|
}) {
|
||||||
|
return `${initial}${delimiter}${postDelimiter}${description}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./commentParserToESTree').JsdocTypeLine} node
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
JsdocTypeLine ({
|
||||||
|
initial, delimiter, postDelimiter, rawType
|
||||||
|
}) {
|
||||||
|
return `${initial}${delimiter}${postDelimiter}${rawType}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./commentParserToESTree').JsdocInlineTag} node
|
||||||
|
*/
|
||||||
|
JsdocInlineTag ({format, namepathOrURL, tag, text}) {
|
||||||
|
return format === 'pipe'
|
||||||
|
? `{@${tag} ${namepathOrURL}|${text}}`
|
||||||
|
: format === 'plain'
|
||||||
|
? `{@${tag} ${namepathOrURL}}`
|
||||||
|
: format === 'prefix'
|
||||||
|
? `[${text}]{@${tag} ${namepathOrURL}}`
|
||||||
|
// "space"
|
||||||
|
: `{@${tag} ${namepathOrURL} ${text}}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
JsdocTag
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo convert for use by escodegen (until may be patched to support
|
||||||
|
* custom entries?).
|
||||||
|
* @param {import('./commentParserToESTree').JsdocBlock|
|
||||||
|
* import('./commentParserToESTree').JsdocDescriptionLine|
|
||||||
|
* import('./commentParserToESTree').JsdocTypeLine|
|
||||||
|
* import('./commentParserToESTree').JsdocTag|
|
||||||
|
* import('./commentParserToESTree').JsdocInlineTag|
|
||||||
|
* import('jsdoc-type-pratt-parser').RootResult
|
||||||
|
* } node
|
||||||
|
* @param {import('.').ESTreeToStringOptions} opts
|
||||||
|
* @throws {Error}
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function estreeToString (node, opts = {}) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(stringifiers, node.type)) {
|
||||||
|
return stringifiers[
|
||||||
|
/**
|
||||||
|
* @type {import('./commentParserToESTree').JsdocBlock|
|
||||||
|
* import('./commentParserToESTree').JsdocDescriptionLine|
|
||||||
|
* import('./commentParserToESTree').JsdocTypeLine|
|
||||||
|
* import('./commentParserToESTree').JsdocTag}
|
||||||
|
*/
|
||||||
|
(node).type
|
||||||
|
](
|
||||||
|
node,
|
||||||
|
opts
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use raw type instead but it is a key as other apps may wish to traverse
|
||||||
|
if (node.type.startsWith('JsdocType')) {
|
||||||
|
return opts.preferRawType
|
||||||
|
? ''
|
||||||
|
: `{${prattStringify(
|
||||||
|
/** @type {import('jsdoc-type-pratt-parser').RootResult} */ (
|
||||||
|
node
|
||||||
|
)
|
||||||
|
)}}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unhandled node type: ${node.type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./commentParserToESTree').JsdocBlock} node
|
||||||
|
* @param {import('.').ESTreeToStringOptions} opts
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function JsdocBlock (node, opts) {
|
||||||
|
const {delimiter, delimiterLineBreak, descriptionLines,
|
||||||
|
initial, postDelimiter, preterminalLineBreak, tags, terminal} = node;
|
||||||
|
|
||||||
|
const terminalPrepend = preterminalLineBreak !== ''
|
||||||
|
? `${preterminalLineBreak}${initial} `
|
||||||
|
: '';
|
||||||
|
|
||||||
|
let result = `${initial}${delimiter}${postDelimiter}${delimiterLineBreak}`;
|
||||||
|
|
||||||
|
for (let i = 0; i < descriptionLines.length; i++) {
|
||||||
|
result += estreeToString(descriptionLines[i]);
|
||||||
|
|
||||||
|
if (i !== descriptionLines.length - 1 || tags.length) {
|
||||||
|
result += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < tags.length; i++) {
|
||||||
|
result += estreeToString(tags[i], opts);
|
||||||
|
|
||||||
|
if (i !== tags.length - 1) {
|
||||||
|
result += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result += `${terminalPrepend}${terminal}`;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./commentParserToESTree').JsdocTag} node
|
||||||
|
* @param {import('.').ESTreeToStringOptions} opts
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function JsdocTag (node, opts) {
|
||||||
|
const {
|
||||||
|
delimiter, descriptionLines, initial, name, parsedType, postDelimiter,
|
||||||
|
postName, postTag, postType, tag, typeLines
|
||||||
|
} = node;
|
||||||
|
|
||||||
|
let result = `${initial}${delimiter}${postDelimiter}@${tag}${postTag}`;
|
||||||
|
|
||||||
|
// Could do `rawType` but may have been changed; could also do
|
||||||
|
// `typeLines` but not as likely to be changed
|
||||||
|
// parsedType
|
||||||
|
// Comment this out later in favor of `parsedType`
|
||||||
|
// We can't use raw `typeLines` as first argument has delimiter on it
|
||||||
|
if (opts.preferRawType || !parsedType) {
|
||||||
|
if (typeLines.length) {
|
||||||
|
result += '{';
|
||||||
|
|
||||||
|
for (let i = 0; i < typeLines.length; i++) {
|
||||||
|
result += estreeToString(typeLines[i]);
|
||||||
|
|
||||||
|
if (i !== typeLines.length - 1) {
|
||||||
|
result += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result += '}';
|
||||||
|
}
|
||||||
|
} else if (parsedType?.type.startsWith('JsdocType')) {
|
||||||
|
result += `{${prattStringify(
|
||||||
|
/** @type {import('jsdoc-type-pratt-parser').RootResult} */ (
|
||||||
|
parsedType
|
||||||
|
)
|
||||||
|
)}}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += name ? `${postType}${name}${postName}` : postType;
|
||||||
|
|
||||||
|
for (let i = 0; i < descriptionLines.length; i++) {
|
||||||
|
const descriptionLine = descriptionLines[i];
|
||||||
|
|
||||||
|
result += estreeToString(descriptionLine);
|
||||||
|
|
||||||
|
if (i !== descriptionLines.length - 1) {
|
||||||
|
result += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {estreeToString};
|
50
node_modules/@es-joy/jsdoccomment/src/index.js
generated
vendored
Normal file
50
node_modules/@es-joy/jsdoccomment/src/index.js
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* @typedef {import('./commentParserToESTree').JsdocInlineTagNoType & {
|
||||||
|
* start: number,
|
||||||
|
* end: number,
|
||||||
|
* }} InlineTag
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('comment-parser').Spec & {
|
||||||
|
* line?: import('./commentParserToESTree').Integer,
|
||||||
|
* inlineTags: (import('./commentParserToESTree').JsdocInlineTagNoType & {
|
||||||
|
* line?: import('./commentParserToESTree').Integer
|
||||||
|
* })[]
|
||||||
|
* }} JsdocTagWithInline
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expands on comment-parser's `Block` interface.
|
||||||
|
* @typedef {{
|
||||||
|
* description: string,
|
||||||
|
* source: import('comment-parser').Line[],
|
||||||
|
* problems: import('comment-parser').Problem[],
|
||||||
|
* tags: JsdocTagWithInline[],
|
||||||
|
* inlineTags: (import('./commentParserToESTree').JsdocInlineTagNoType & {
|
||||||
|
* line?: import('./commentParserToESTree').Integer
|
||||||
|
* })[]
|
||||||
|
* }} JsdocBlockWithInline
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{preferRawType?: boolean}} ESTreeToStringOptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback CommentHandler
|
||||||
|
* @param {string} commentSelector
|
||||||
|
* @param {import('.').JsdocBlockWithInline} jsdoc
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export {visitorKeys as jsdocTypeVisitorKeys} from 'jsdoc-type-pratt-parser';
|
||||||
|
|
||||||
|
export * from 'jsdoc-type-pratt-parser';
|
||||||
|
|
||||||
|
export * from './commentHandler.js';
|
||||||
|
export * from './commentParserToESTree.js';
|
||||||
|
export * from './estreeToString.js';
|
||||||
|
export * from './jsdoccomment.js';
|
||||||
|
export * from './parseComment.js';
|
||||||
|
export * from './parseInlineTags.js';
|
487
node_modules/@es-joy/jsdoccomment/src/jsdoccomment.js
generated
vendored
Normal file
487
node_modules/@es-joy/jsdoccomment/src/jsdoccomment.js
generated
vendored
Normal file
@ -0,0 +1,487 @@
|
|||||||
|
/**
|
||||||
|
* Obtained originally from {@link https://github.com/eslint/eslint/blob/master/lib/util/source-code.js#L313}.
|
||||||
|
*
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('eslint').AST.Token | import('estree').Comment | {
|
||||||
|
* type: import('eslint').AST.TokenType|"Line"|"Block"|"Shebang",
|
||||||
|
* range: [number, number],
|
||||||
|
* value: string
|
||||||
|
* }} Token
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('eslint').Rule.Node|
|
||||||
|
* import('@typescript-eslint/types').TSESTree.Node} ESLintOrTSNode
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {number} int
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given token is a comment token or not.
|
||||||
|
*
|
||||||
|
* @param {Token} token - The token to check.
|
||||||
|
* @returns {boolean} `true` if the token is a comment token.
|
||||||
|
*/
|
||||||
|
const isCommentToken = (token) => {
|
||||||
|
return token.type === 'Line' || token.type === 'Block' ||
|
||||||
|
token.type === 'Shebang';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {(ESLintOrTSNode|import('estree').Comment) & {
|
||||||
|
* declaration?: any,
|
||||||
|
* decorators?: any[],
|
||||||
|
* parent?: import('eslint').Rule.Node & {
|
||||||
|
* decorators?: any[]
|
||||||
|
* }
|
||||||
|
* }} node
|
||||||
|
* @returns {import('@typescript-eslint/types').TSESTree.Decorator|undefined}
|
||||||
|
*/
|
||||||
|
const getDecorator = (node) => {
|
||||||
|
return node?.declaration?.decorators?.[0] || node?.decorators?.[0] ||
|
||||||
|
node?.parent?.decorators?.[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if it is a ES6 export declaration.
|
||||||
|
*
|
||||||
|
* @param {ESLintOrTSNode} astNode An AST node.
|
||||||
|
* @returns {boolean} whether the given node represents an export declaration.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const looksLikeExport = function (astNode) {
|
||||||
|
return astNode.type === 'ExportDefaultDeclaration' ||
|
||||||
|
astNode.type === 'ExportNamedDeclaration' ||
|
||||||
|
astNode.type === 'ExportAllDeclaration' ||
|
||||||
|
astNode.type === 'ExportSpecifier';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ESLintOrTSNode} astNode
|
||||||
|
* @returns {ESLintOrTSNode}
|
||||||
|
*/
|
||||||
|
const getTSFunctionComment = function (astNode) {
|
||||||
|
const {parent} = astNode;
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (!parent) {
|
||||||
|
return astNode;
|
||||||
|
}
|
||||||
|
const grandparent = parent.parent;
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (!grandparent) {
|
||||||
|
return astNode;
|
||||||
|
}
|
||||||
|
const greatGrandparent = grandparent.parent;
|
||||||
|
const greatGreatGrandparent = greatGrandparent && greatGrandparent.parent;
|
||||||
|
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (/** @type {ESLintOrTSNode} */ (parent).type !== 'TSTypeAnnotation') {
|
||||||
|
return astNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (/** @type {ESLintOrTSNode} */ (grandparent).type) {
|
||||||
|
// @ts-expect-error -- For `ClassProperty`.
|
||||||
|
case 'PropertyDefinition': case 'ClassProperty':
|
||||||
|
case 'TSDeclareFunction':
|
||||||
|
case 'TSMethodSignature':
|
||||||
|
case 'TSPropertySignature':
|
||||||
|
return grandparent;
|
||||||
|
case 'ArrowFunctionExpression':
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (!greatGrandparent) {
|
||||||
|
return astNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
greatGrandparent.type === 'VariableDeclarator'
|
||||||
|
|
||||||
|
// && greatGreatGrandparent.parent.type === 'VariableDeclaration'
|
||||||
|
) {
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (!greatGreatGrandparent || !greatGreatGrandparent.parent) {
|
||||||
|
return astNode;
|
||||||
|
}
|
||||||
|
return greatGreatGrandparent.parent;
|
||||||
|
}
|
||||||
|
/* v8 ignore next */
|
||||||
|
return astNode;
|
||||||
|
case 'FunctionExpression':
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (!greatGreatGrandparent) {
|
||||||
|
return astNode;
|
||||||
|
}
|
||||||
|
if (greatGrandparent.type === 'MethodDefinition') {
|
||||||
|
return greatGrandparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough
|
||||||
|
default:
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (grandparent.type !== 'Identifier') {
|
||||||
|
return astNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (!greatGreatGrandparent) {
|
||||||
|
return astNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (greatGrandparent.type) {
|
||||||
|
case 'ArrowFunctionExpression':
|
||||||
|
if (
|
||||||
|
greatGreatGrandparent.type === 'VariableDeclarator' &&
|
||||||
|
greatGreatGrandparent.parent.type === 'VariableDeclaration'
|
||||||
|
) {
|
||||||
|
return greatGreatGrandparent.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return astNode;
|
||||||
|
case 'FunctionDeclaration':
|
||||||
|
return greatGrandparent;
|
||||||
|
case 'VariableDeclarator':
|
||||||
|
if (greatGreatGrandparent.type === 'VariableDeclaration') {
|
||||||
|
return greatGreatGrandparent;
|
||||||
|
}
|
||||||
|
/* v8 ignore next 2 */
|
||||||
|
// Fallthrough
|
||||||
|
default:
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
return astNode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const invokedExpression = new Set(
|
||||||
|
['CallExpression', 'OptionalCallExpression', 'NewExpression']
|
||||||
|
);
|
||||||
|
const allowableCommentNode = new Set([
|
||||||
|
'AssignmentPattern',
|
||||||
|
'VariableDeclaration',
|
||||||
|
'ExpressionStatement',
|
||||||
|
'MethodDefinition',
|
||||||
|
'Property',
|
||||||
|
'ObjectProperty',
|
||||||
|
'ClassProperty',
|
||||||
|
'PropertyDefinition',
|
||||||
|
'ExportDefaultDeclaration',
|
||||||
|
'ReturnStatement'
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces the provided node to the appropriate node for evaluating
|
||||||
|
* JSDoc comment status.
|
||||||
|
*
|
||||||
|
* @param {ESLintOrTSNode} node An AST node.
|
||||||
|
* @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode.
|
||||||
|
* @returns {ESLintOrTSNode} The AST node that
|
||||||
|
* can be evaluated for appropriate JSDoc comments.
|
||||||
|
*/
|
||||||
|
const getReducedASTNode = function (node, sourceCode) {
|
||||||
|
let {parent} = node;
|
||||||
|
|
||||||
|
switch (/** @type {ESLintOrTSNode} */ (node).type) {
|
||||||
|
case 'TSFunctionType':
|
||||||
|
return getTSFunctionComment(node);
|
||||||
|
case 'TSInterfaceDeclaration':
|
||||||
|
case 'TSTypeAliasDeclaration':
|
||||||
|
case 'TSEnumDeclaration':
|
||||||
|
case 'ClassDeclaration':
|
||||||
|
case 'FunctionDeclaration':
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (!parent) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
return looksLikeExport(parent) ? parent : node;
|
||||||
|
|
||||||
|
case 'TSDeclareFunction':
|
||||||
|
case 'ClassExpression':
|
||||||
|
case 'ObjectExpression':
|
||||||
|
case 'ArrowFunctionExpression':
|
||||||
|
case 'TSEmptyBodyFunctionExpression':
|
||||||
|
case 'FunctionExpression':
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (!parent) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!invokedExpression.has(parent.type)
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* @type {ESLintOrTSNode|Token|null}
|
||||||
|
*/
|
||||||
|
let token = node;
|
||||||
|
do {
|
||||||
|
token = sourceCode.getTokenBefore(
|
||||||
|
/** @type {import('eslint').Rule.Node|import('eslint').AST.Token} */ (
|
||||||
|
token
|
||||||
|
),
|
||||||
|
{includeComments: true}
|
||||||
|
);
|
||||||
|
} while (token && token.type === 'Punctuator' && token.value === '(');
|
||||||
|
if (token && token.type === 'Block') {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceCode.getCommentsBefore(
|
||||||
|
/** @type {import('eslint').Rule.Node} */
|
||||||
|
(node)
|
||||||
|
).length) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (
|
||||||
|
!sourceCode.getCommentsBefore(
|
||||||
|
/** @type {import('eslint').Rule.Node} */
|
||||||
|
(parent)
|
||||||
|
).length &&
|
||||||
|
!(/Function/u).test(parent.type) &&
|
||||||
|
!allowableCommentNode.has(parent.type)
|
||||||
|
) {
|
||||||
|
({parent} = parent);
|
||||||
|
|
||||||
|
if (!parent) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parent && parent.type !== 'FunctionDeclaration' &&
|
||||||
|
parent.type !== 'Program'
|
||||||
|
) {
|
||||||
|
if (parent.parent && parent.parent.type === 'ExportNamedDeclaration') {
|
||||||
|
return parent.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for the presence of a JSDoc comment for the given node and returns it.
|
||||||
|
*
|
||||||
|
* @param {ESLintOrTSNode} astNode The AST node to get
|
||||||
|
* the comment for.
|
||||||
|
* @param {import('eslint').SourceCode} sourceCode
|
||||||
|
* @param {{maxLines: int, minLines: int, [name: string]: any}} settings
|
||||||
|
* @param {{nonJSDoc?: boolean}} [opts]
|
||||||
|
* @returns {Token|null} The Block comment token containing the JSDoc comment
|
||||||
|
* for the given node or null if not found.
|
||||||
|
*/
|
||||||
|
const findJSDocComment = (astNode, sourceCode, settings, opts = {}) => {
|
||||||
|
const {nonJSDoc} = opts;
|
||||||
|
const {minLines, maxLines} = settings;
|
||||||
|
|
||||||
|
/** @type {ESLintOrTSNode|import('estree').Comment} */
|
||||||
|
let currentNode = astNode;
|
||||||
|
let tokenBefore = null;
|
||||||
|
let parenthesisToken = null;
|
||||||
|
|
||||||
|
while (currentNode) {
|
||||||
|
const decorator = getDecorator(
|
||||||
|
/** @type {import('eslint').Rule.Node} */
|
||||||
|
(currentNode)
|
||||||
|
);
|
||||||
|
if (decorator) {
|
||||||
|
const dec = /** @type {unknown} */ (decorator);
|
||||||
|
currentNode = /** @type {import('eslint').Rule.Node} */ (dec);
|
||||||
|
}
|
||||||
|
tokenBefore = sourceCode.getTokenBefore(
|
||||||
|
/** @type {import('eslint').Rule.Node} */
|
||||||
|
(currentNode),
|
||||||
|
{includeComments: true}
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
tokenBefore && tokenBefore.type === 'Punctuator' &&
|
||||||
|
tokenBefore.value === '('
|
||||||
|
) {
|
||||||
|
parenthesisToken = tokenBefore;
|
||||||
|
[tokenBefore] = sourceCode.getTokensBefore(
|
||||||
|
/** @type {import('eslint').Rule.Node} */
|
||||||
|
(currentNode),
|
||||||
|
{
|
||||||
|
count: 2,
|
||||||
|
includeComments: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!tokenBefore || !isCommentToken(tokenBefore)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!nonJSDoc && tokenBefore.type === 'Line') {
|
||||||
|
currentNode = tokenBefore;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
if (!tokenBefore || !currentNode.loc || !tokenBefore.loc) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(
|
||||||
|
(nonJSDoc && (tokenBefore.type !== 'Block' ||
|
||||||
|
!(/^\*\s/u).test(tokenBefore.value))) ||
|
||||||
|
(!nonJSDoc && tokenBefore.type === 'Block' &&
|
||||||
|
(/^\*\s/u).test(tokenBefore.value))
|
||||||
|
) &&
|
||||||
|
currentNode.loc.start.line - (
|
||||||
|
/** @type {import('eslint').AST.Token} */
|
||||||
|
(parenthesisToken ?? tokenBefore)
|
||||||
|
).loc.end.line >= minLines &&
|
||||||
|
currentNode.loc.start.line - (
|
||||||
|
/** @type {import('eslint').AST.Token} */
|
||||||
|
(parenthesisToken ?? tokenBefore)
|
||||||
|
).loc.end.line <= maxLines
|
||||||
|
) {
|
||||||
|
return tokenBefore;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the JSDoc comment for a given node.
|
||||||
|
*
|
||||||
|
* @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode
|
||||||
|
* @param {import('eslint').Rule.Node} node The AST node to get
|
||||||
|
* the comment for.
|
||||||
|
* @param {{maxLines: int, minLines: int, [name: string]: any}} settings The
|
||||||
|
* settings in context
|
||||||
|
* @returns {Token|null} The Block comment
|
||||||
|
* token containing the JSDoc comment for the given node or
|
||||||
|
* null if not found.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
const getJSDocComment = function (sourceCode, node, settings) {
|
||||||
|
const reducedNode = getReducedASTNode(node, sourceCode);
|
||||||
|
|
||||||
|
return findJSDocComment(reducedNode, sourceCode, settings);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the comment preceding a given node.
|
||||||
|
*
|
||||||
|
* @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode
|
||||||
|
* @param {ESLintOrTSNode} node The AST node to get
|
||||||
|
* the comment for.
|
||||||
|
* @param {{maxLines: int, minLines: int, [name: string]: any}} settings The
|
||||||
|
* settings in context
|
||||||
|
* @returns {Token|null} The Block comment
|
||||||
|
* token containing the JSDoc comment for the given node or
|
||||||
|
* null if not found.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
const getNonJsdocComment = function (sourceCode, node, settings) {
|
||||||
|
const reducedNode = getReducedASTNode(node, sourceCode);
|
||||||
|
|
||||||
|
return findJSDocComment(reducedNode, sourceCode, settings, {
|
||||||
|
nonJSDoc: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ESLintOrTSNode|import('eslint').AST.Token|
|
||||||
|
* import('estree').Comment
|
||||||
|
* } nodeA The AST node or token to compare
|
||||||
|
* @param {ESLintOrTSNode|import('eslint').AST.Token|
|
||||||
|
* import('estree').Comment} nodeB The
|
||||||
|
* AST node or token to compare
|
||||||
|
*/
|
||||||
|
const compareLocEndToStart = (nodeA, nodeB) => {
|
||||||
|
/* v8 ignore next */
|
||||||
|
return (nodeA.loc?.end.line ?? 0) === (nodeB.loc?.start.line ?? 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for the presence of a comment following the given node and
|
||||||
|
* returns it.
|
||||||
|
*
|
||||||
|
* This method is experimental.
|
||||||
|
*
|
||||||
|
* @param {import('eslint').SourceCode} sourceCode
|
||||||
|
* @param {ESLintOrTSNode} astNode The AST node to get
|
||||||
|
* the comment for.
|
||||||
|
* @returns {Token|null} The comment token containing the comment
|
||||||
|
* for the given node or null if not found.
|
||||||
|
*/
|
||||||
|
const getFollowingComment = function (sourceCode, astNode) {
|
||||||
|
/**
|
||||||
|
* @param {ESLintOrTSNode} node The
|
||||||
|
* AST node to get the comment for.
|
||||||
|
*/
|
||||||
|
const getTokensAfterIgnoringSemis = (node) => {
|
||||||
|
let tokenAfter = sourceCode.getTokenAfter(
|
||||||
|
/** @type {import('eslint').Rule.Node} */
|
||||||
|
(node),
|
||||||
|
{includeComments: true}
|
||||||
|
);
|
||||||
|
|
||||||
|
while (
|
||||||
|
tokenAfter && tokenAfter.type === 'Punctuator' &&
|
||||||
|
// tokenAfter.value === ')' // Don't apparently need to ignore
|
||||||
|
tokenAfter.value === ';'
|
||||||
|
) {
|
||||||
|
[tokenAfter] = sourceCode.getTokensAfter(tokenAfter, {
|
||||||
|
includeComments: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return tokenAfter;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ESLintOrTSNode} node The
|
||||||
|
* AST node to get the comment for.
|
||||||
|
*/
|
||||||
|
const tokenAfterIgnoringSemis = (node) => {
|
||||||
|
const tokenAfter = getTokensAfterIgnoringSemis(node);
|
||||||
|
return (
|
||||||
|
tokenAfter &&
|
||||||
|
isCommentToken(tokenAfter) &&
|
||||||
|
compareLocEndToStart(node, tokenAfter)
|
||||||
|
)
|
||||||
|
? tokenAfter
|
||||||
|
: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
let tokenAfter = tokenAfterIgnoringSemis(astNode);
|
||||||
|
|
||||||
|
if (!tokenAfter) {
|
||||||
|
switch (astNode.type) {
|
||||||
|
case 'FunctionDeclaration':
|
||||||
|
tokenAfter = tokenAfterIgnoringSemis(
|
||||||
|
/** @type {ESLintOrTSNode} */
|
||||||
|
(astNode.body)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'ExpressionStatement':
|
||||||
|
tokenAfter = tokenAfterIgnoringSemis(
|
||||||
|
/** @type {ESLintOrTSNode} */
|
||||||
|
(astNode.expression)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* v8 ignore next 3 */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenAfter;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
getReducedASTNode, getJSDocComment, getNonJsdocComment,
|
||||||
|
getDecorator, findJSDocComment, getFollowingComment
|
||||||
|
};
|
190
node_modules/@es-joy/jsdoccomment/src/parseComment.js
generated
vendored
Normal file
190
node_modules/@es-joy/jsdoccomment/src/parseComment.js
generated
vendored
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
/* eslint-disable prefer-named-capture-group -- Temporary */
|
||||||
|
import {
|
||||||
|
parse as commentParser,
|
||||||
|
tokenizers
|
||||||
|
} from 'comment-parser';
|
||||||
|
|
||||||
|
import {parseInlineTags} from './parseInlineTags.js';
|
||||||
|
|
||||||
|
const {
|
||||||
|
name: nameTokenizer,
|
||||||
|
tag: tagTokenizer,
|
||||||
|
type: typeTokenizer,
|
||||||
|
description: descriptionTokenizer
|
||||||
|
} = tokenizers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('comment-parser').Spec} spec
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export const hasSeeWithLink = (spec) => {
|
||||||
|
return spec.tag === 'see' && (/\{@link.+?\}/u).test(spec.source[0].source);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultNoTypes = [
|
||||||
|
'default', 'defaultvalue', 'description', 'example',
|
||||||
|
'file', 'fileoverview', 'license',
|
||||||
|
'overview', 'see', 'summary'
|
||||||
|
];
|
||||||
|
|
||||||
|
export const defaultNoNames = [
|
||||||
|
'access', 'author',
|
||||||
|
'default', 'defaultvalue',
|
||||||
|
'description',
|
||||||
|
'example', 'exception', 'file', 'fileoverview',
|
||||||
|
'kind',
|
||||||
|
'license', 'overview',
|
||||||
|
'return', 'returns',
|
||||||
|
'since', 'summary',
|
||||||
|
'throws',
|
||||||
|
'version', 'variation'
|
||||||
|
];
|
||||||
|
|
||||||
|
const optionalBrackets = /^\[(?<name>[^=]*)=[^\]]*\]/u;
|
||||||
|
const preserveTypeTokenizer = typeTokenizer('preserve');
|
||||||
|
const preserveDescriptionTokenizer = descriptionTokenizer('preserve');
|
||||||
|
const plainNameTokenizer = nameTokenizer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can't import `comment-parser/es6/parser/tokenizers/index.js`,
|
||||||
|
* so we redefine here.
|
||||||
|
* @typedef {(spec: import('comment-parser').Spec) =>
|
||||||
|
* import('comment-parser').Spec} CommentParserTokenizer
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} [cfg]
|
||||||
|
* @param {string[]} [cfg.noTypes]
|
||||||
|
* @param {string[]} [cfg.noNames]
|
||||||
|
* @returns {CommentParserTokenizer[]}
|
||||||
|
*/
|
||||||
|
const getTokenizers = ({
|
||||||
|
noTypes = defaultNoTypes,
|
||||||
|
noNames = defaultNoNames
|
||||||
|
} = {}) => {
|
||||||
|
// trim
|
||||||
|
return [
|
||||||
|
// Tag
|
||||||
|
tagTokenizer(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type tokenizer.
|
||||||
|
* @param {import('comment-parser').Spec} spec
|
||||||
|
* @returns {import('comment-parser').Spec}
|
||||||
|
*/
|
||||||
|
(spec) => {
|
||||||
|
if (noTypes.includes(spec.tag)) {
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return preserveTypeTokenizer(spec);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name tokenizer.
|
||||||
|
* @param {import('comment-parser').Spec} spec
|
||||||
|
* @returns {import('comment-parser').Spec}
|
||||||
|
*/
|
||||||
|
(spec) => {
|
||||||
|
if (spec.tag === 'template') {
|
||||||
|
// const preWS = spec.postTag;
|
||||||
|
const remainder = spec.source[0].tokens.description;
|
||||||
|
|
||||||
|
let pos;
|
||||||
|
if (remainder.startsWith('[') && remainder.includes(']')) {
|
||||||
|
const endingBracketPos = remainder.indexOf(']');
|
||||||
|
pos = remainder.slice(endingBracketPos).search(/(?<![\s,])\s/u);
|
||||||
|
if (pos > -1) { // Add offset to starting point if space found
|
||||||
|
pos += endingBracketPos;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pos = remainder.search(/(?<![\s,])\s/u);
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = pos === -1 ? remainder : remainder.slice(0, pos);
|
||||||
|
const extra = remainder.slice(pos);
|
||||||
|
let postName = '', description = '', lineEnd = '';
|
||||||
|
if (pos > -1) {
|
||||||
|
[, postName, description, lineEnd] = /** @type {RegExpMatchArray} */ (
|
||||||
|
extra.match(/(\s*)([^\r]*)(\r)?/u)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optionalBrackets.test(name)) {
|
||||||
|
name = /** @type {string} */ (
|
||||||
|
/** @type {RegExpMatchArray} */ (
|
||||||
|
name.match(optionalBrackets)
|
||||||
|
)?.groups?.name
|
||||||
|
);
|
||||||
|
spec.optional = true;
|
||||||
|
} else {
|
||||||
|
spec.optional = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
spec.name = name;
|
||||||
|
const {tokens} = spec.source[0];
|
||||||
|
tokens.name = name;
|
||||||
|
tokens.postName = postName;
|
||||||
|
tokens.description = description;
|
||||||
|
tokens.lineEnd = lineEnd || '';
|
||||||
|
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noNames.includes(spec.tag) || hasSeeWithLink(spec)) {
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return plainNameTokenizer(spec);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description tokenizer.
|
||||||
|
* @param {import('comment-parser').Spec} spec
|
||||||
|
* @returns {import('comment-parser').Spec}
|
||||||
|
*/
|
||||||
|
(spec) => {
|
||||||
|
return preserveDescriptionTokenizer(spec);
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts a comment token or complete comment string and converts it into
|
||||||
|
* `comment-parser` AST.
|
||||||
|
* @param {string | {value: string}} commentOrNode
|
||||||
|
* @param {string} [indent] Whitespace
|
||||||
|
* @returns {import('.').JsdocBlockWithInline}
|
||||||
|
*/
|
||||||
|
const parseComment = (commentOrNode, indent = '') => {
|
||||||
|
let block;
|
||||||
|
|
||||||
|
switch (typeof commentOrNode) {
|
||||||
|
case 'string':
|
||||||
|
// Preserve JSDoc block start/end indentation.
|
||||||
|
[block] = commentParser(`${indent}${commentOrNode}`, {
|
||||||
|
// @see https://github.com/yavorskiy/comment-parser/issues/21
|
||||||
|
tokenizers: getTokenizers()
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'object':
|
||||||
|
if (commentOrNode === null) {
|
||||||
|
throw new TypeError(`'commentOrNode' is not a string or object.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve JSDoc block start/end indentation.
|
||||||
|
[block] = commentParser(`${indent}/*${commentOrNode.value}*/`, {
|
||||||
|
// @see https://github.com/yavorskiy/comment-parser/issues/21
|
||||||
|
tokenizers: getTokenizers()
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new TypeError(`'commentOrNode' is not a string or object.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseInlineTags(block);
|
||||||
|
};
|
||||||
|
|
||||||
|
export {getTokenizers, parseComment};
|
108
node_modules/@es-joy/jsdoccomment/src/parseInlineTags.js
generated
vendored
Normal file
108
node_modules/@es-joy/jsdoccomment/src/parseInlineTags.js
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* @param {RegExpMatchArray & {
|
||||||
|
* indices: {
|
||||||
|
* groups: {
|
||||||
|
* [key: string]: [number, number]
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* groups: {[key: string]: string}
|
||||||
|
* }} match An inline tag regexp match.
|
||||||
|
* @returns {'pipe' | 'plain' | 'prefix' | 'space'}
|
||||||
|
*/
|
||||||
|
function determineFormat (match) {
|
||||||
|
const {separator, text} = match.groups;
|
||||||
|
const [, textEnd] = match.indices.groups.text;
|
||||||
|
const [tagStart] = match.indices.groups.tag;
|
||||||
|
if (!text) {
|
||||||
|
return 'plain';
|
||||||
|
} else if (separator === '|') {
|
||||||
|
return 'pipe';
|
||||||
|
} else if (textEnd < tagStart) {
|
||||||
|
return 'prefix';
|
||||||
|
}
|
||||||
|
return 'space';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts inline tags from a description.
|
||||||
|
* @param {string} description
|
||||||
|
* @returns {import('.').InlineTag[]} Array of inline tags from the description.
|
||||||
|
*/
|
||||||
|
function parseDescription (description) {
|
||||||
|
/** @type {import('.').InlineTag[]} */
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
// This could have been expressed in a single pattern,
|
||||||
|
// but having two avoids a potentially exponential time regex.
|
||||||
|
|
||||||
|
const prefixedTextPattern = new RegExp(/(?:\[(?<text>[^\]]+)\])\{@(?<tag>[^}\s]+)\s?(?<namepathOrURL>[^}\s|]*)\}/gu, 'gud');
|
||||||
|
// The pattern used to match for text after tag uses a negative lookbehind
|
||||||
|
// on the ']' char to avoid matching the prefixed case too.
|
||||||
|
const suffixedAfterPattern = new RegExp(/(?<!\])\{@(?<tag>[^}\s]+)\s?(?<namepathOrURL>[^}\s|]*)\s*(?<separator>[\s|])?\s*(?<text>[^}]*)\}/gu, 'gud');
|
||||||
|
|
||||||
|
const matches = [
|
||||||
|
...description.matchAll(prefixedTextPattern),
|
||||||
|
...description.matchAll(suffixedAfterPattern)
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const mtch of matches) {
|
||||||
|
const match = /**
|
||||||
|
* @type {RegExpMatchArray & {
|
||||||
|
* indices: {
|
||||||
|
* groups: {
|
||||||
|
* [key: string]: [number, number]
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* groups: {[key: string]: string}
|
||||||
|
* }}
|
||||||
|
*/ (
|
||||||
|
mtch
|
||||||
|
);
|
||||||
|
const {tag, namepathOrURL, text} = match.groups;
|
||||||
|
const [start, end] = match.indices[0];
|
||||||
|
const format = determineFormat(match);
|
||||||
|
|
||||||
|
result.push({
|
||||||
|
tag,
|
||||||
|
namepathOrURL,
|
||||||
|
text,
|
||||||
|
format,
|
||||||
|
start,
|
||||||
|
end
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits the `{@prefix}` from remaining `Spec.lines[].token.description`
|
||||||
|
* into the `inlineTags` tokens, and populates `spec.inlineTags`
|
||||||
|
* @param {import('comment-parser').Block} block
|
||||||
|
* @returns {import('.').JsdocBlockWithInline}
|
||||||
|
*/
|
||||||
|
export function parseInlineTags (block) {
|
||||||
|
const inlineTags =
|
||||||
|
/**
|
||||||
|
* @type {(import('./commentParserToESTree').JsdocInlineTagNoType & {
|
||||||
|
* line?: import('./commentParserToESTree').Integer
|
||||||
|
* })[]}
|
||||||
|
*/ (
|
||||||
|
parseDescription(block.description)
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @type {import('.').JsdocBlockWithInline} */ (
|
||||||
|
block
|
||||||
|
).inlineTags = inlineTags;
|
||||||
|
|
||||||
|
for (const tag of block.tags) {
|
||||||
|
/**
|
||||||
|
* @type {import('.').JsdocTagWithInline}
|
||||||
|
*/ (tag).inlineTags = parseDescription(tag.description);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
/**
|
||||||
|
* @type {import('.').JsdocBlockWithInline}
|
||||||
|
*/ (block)
|
||||||
|
);
|
||||||
|
}
|
13
node_modules/@es-joy/jsdoccomment/src/toCamelCase.js
generated
vendored
Normal file
13
node_modules/@es-joy/jsdoccomment/src/toCamelCase.js
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
const toCamelCase = (str) => {
|
||||||
|
return str.toLowerCase().replaceAll(/^[a-z]/gu, (init) => {
|
||||||
|
return init.toUpperCase();
|
||||||
|
}).replaceAll(/_(?<wordInit>[a-z])/gu, (_, n1, o, s, {wordInit}) => {
|
||||||
|
return wordInit.toUpperCase();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {toCamelCase};
|
21
node_modules/@eslint-community/eslint-utils/LICENSE
generated
vendored
Normal file
21
node_modules/@eslint-community/eslint-utils/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Toru Nagashima
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
37
node_modules/@eslint-community/eslint-utils/README.md
generated
vendored
Normal file
37
node_modules/@eslint-community/eslint-utils/README.md
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# @eslint-community/eslint-utils
|
||||||
|
|
||||||
|
[![npm version](https://img.shields.io/npm/v/@eslint-community/eslint-utils.svg)](https://www.npmjs.com/package/@eslint-community/eslint-utils)
|
||||||
|
[![Downloads/month](https://img.shields.io/npm/dm/@eslint-community/eslint-utils.svg)](http://www.npmtrends.com/@eslint-community/eslint-utils)
|
||||||
|
[![Build Status](https://github.com/eslint-community/eslint-utils/workflows/CI/badge.svg)](https://github.com/eslint-community/eslint-utils/actions)
|
||||||
|
[![Coverage Status](https://codecov.io/gh/eslint-community/eslint-utils/branch/main/graph/badge.svg)](https://codecov.io/gh/eslint-community/eslint-utils)
|
||||||
|
|
||||||
|
## 🏁 Goal
|
||||||
|
|
||||||
|
This package provides utility functions and classes for make ESLint custom rules.
|
||||||
|
|
||||||
|
For examples:
|
||||||
|
|
||||||
|
- [`getStaticValue`](https://eslint-community.github.io/eslint-utils/api/ast-utils.html#getstaticvalue) evaluates static value on AST.
|
||||||
|
- [`ReferenceTracker`](https://eslint-community.github.io/eslint-utils/api/scope-utils.html#referencetracker-class) checks the members of modules/globals as handling assignments and destructuring.
|
||||||
|
|
||||||
|
## 📖 Usage
|
||||||
|
|
||||||
|
See [documentation](https://eslint-community.github.io/eslint-utils).
|
||||||
|
|
||||||
|
## 📰 Changelog
|
||||||
|
|
||||||
|
See [releases](https://github.com/eslint-community/eslint-utils/releases).
|
||||||
|
|
||||||
|
## ❤️ Contributing
|
||||||
|
|
||||||
|
Welcome contributing!
|
||||||
|
|
||||||
|
Please use GitHub's Issues/PRs.
|
||||||
|
|
||||||
|
### Development Tools
|
||||||
|
|
||||||
|
- `npm test` runs tests and measures coverage.
|
||||||
|
- `npm run clean` removes the coverage result of `npm test` command.
|
||||||
|
- `npm run coverage` shows the coverage result of the last `npm test` command.
|
||||||
|
- `npm run lint` runs ESLint.
|
||||||
|
- `npm run watch` runs tests on each file change.
|
2059
node_modules/@eslint-community/eslint-utils/index.js
generated
vendored
Normal file
2059
node_modules/@eslint-community/eslint-utils/index.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
node_modules/@eslint-community/eslint-utils/index.js.map
generated
vendored
Normal file
1
node_modules/@eslint-community/eslint-utils/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2018
node_modules/@eslint-community/eslint-utils/index.mjs
generated
vendored
Normal file
2018
node_modules/@eslint-community/eslint-utils/index.mjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
node_modules/@eslint-community/eslint-utils/index.mjs.map
generated
vendored
Normal file
1
node_modules/@eslint-community/eslint-utils/index.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
201
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/LICENSE
generated
vendored
Normal file
201
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright contributors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
105
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/README.md
generated
vendored
Normal file
105
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/README.md
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
# eslint-visitor-keys
|
||||||
|
|
||||||
|
[![npm version](https://img.shields.io/npm/v/eslint-visitor-keys.svg)](https://www.npmjs.com/package/eslint-visitor-keys)
|
||||||
|
[![Downloads/month](https://img.shields.io/npm/dm/eslint-visitor-keys.svg)](http://www.npmtrends.com/eslint-visitor-keys)
|
||||||
|
[![Build Status](https://github.com/eslint/eslint-visitor-keys/workflows/CI/badge.svg)](https://github.com/eslint/eslint-visitor-keys/actions)
|
||||||
|
|
||||||
|
Constants and utilities about visitor keys to traverse AST.
|
||||||
|
|
||||||
|
## 💿 Installation
|
||||||
|
|
||||||
|
Use [npm] to install.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install eslint-visitor-keys
|
||||||
|
```
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- [Node.js] `^12.22.0`, `^14.17.0`, or `>=16.0.0`
|
||||||
|
|
||||||
|
|
||||||
|
## 📖 Usage
|
||||||
|
|
||||||
|
To use in an ESM file:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import * as evk from "eslint-visitor-keys"
|
||||||
|
```
|
||||||
|
|
||||||
|
To use in a CommonJS file:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const evk = require("eslint-visitor-keys")
|
||||||
|
```
|
||||||
|
|
||||||
|
### evk.KEYS
|
||||||
|
|
||||||
|
> type: `{ [type: string]: string[] | undefined }`
|
||||||
|
|
||||||
|
Visitor keys. This keys are frozen.
|
||||||
|
|
||||||
|
This is an object. Keys are the type of [ESTree] nodes. Their values are an array of property names which have child nodes.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
console.log(evk.KEYS.AssignmentExpression) // → ["left", "right"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### evk.getKeys(node)
|
||||||
|
|
||||||
|
> type: `(node: object) => string[]`
|
||||||
|
|
||||||
|
Get the visitor keys of a given AST node.
|
||||||
|
|
||||||
|
This is similar to `Object.keys(node)` of ES Standard, but some keys are excluded: `parent`, `leadingComments`, `trailingComments`, and names which start with `_`.
|
||||||
|
|
||||||
|
This will be used to traverse unknown nodes.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const node = {
|
||||||
|
type: "AssignmentExpression",
|
||||||
|
left: { type: "Identifier", name: "foo" },
|
||||||
|
right: { type: "Literal", value: 0 }
|
||||||
|
}
|
||||||
|
console.log(evk.getKeys(node)) // → ["type", "left", "right"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### evk.unionWith(additionalKeys)
|
||||||
|
|
||||||
|
> type: `(additionalKeys: object) => { [type: string]: string[] | undefined }`
|
||||||
|
|
||||||
|
Make the union set with `evk.KEYS` and the given keys.
|
||||||
|
|
||||||
|
- The order of keys is, `additionalKeys` is at first, then `evk.KEYS` is concatenated after that.
|
||||||
|
- It removes duplicated keys as keeping the first one.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
console.log(evk.unionWith({
|
||||||
|
MethodDefinition: ["decorators"]
|
||||||
|
})) // → { ..., MethodDefinition: ["decorators", "key", "value"], ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📰 Change log
|
||||||
|
|
||||||
|
See [GitHub releases](https://github.com/eslint/eslint-visitor-keys/releases).
|
||||||
|
|
||||||
|
## 🍻 Contributing
|
||||||
|
|
||||||
|
Welcome. See [ESLint contribution guidelines](https://eslint.org/docs/developer-guide/contributing/).
|
||||||
|
|
||||||
|
### Development commands
|
||||||
|
|
||||||
|
- `npm test` runs tests and measures code coverage.
|
||||||
|
- `npm run lint` checks source codes with ESLint.
|
||||||
|
- `npm run test:open-coverage` opens the code coverage report of the previous test with your default browser.
|
||||||
|
|
||||||
|
|
||||||
|
[npm]: https://www.npmjs.com/
|
||||||
|
[Node.js]: https://nodejs.org/
|
||||||
|
[ESTree]: https://github.com/estree/estree
|
384
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.cjs
generated
vendored
Normal file
384
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.cjs
generated
vendored
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{ readonly [type: string]: ReadonlyArray<string> }} VisitorKeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {VisitorKeys}
|
||||||
|
*/
|
||||||
|
const KEYS = {
|
||||||
|
ArrayExpression: [
|
||||||
|
"elements"
|
||||||
|
],
|
||||||
|
ArrayPattern: [
|
||||||
|
"elements"
|
||||||
|
],
|
||||||
|
ArrowFunctionExpression: [
|
||||||
|
"params",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
AssignmentExpression: [
|
||||||
|
"left",
|
||||||
|
"right"
|
||||||
|
],
|
||||||
|
AssignmentPattern: [
|
||||||
|
"left",
|
||||||
|
"right"
|
||||||
|
],
|
||||||
|
AwaitExpression: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
BinaryExpression: [
|
||||||
|
"left",
|
||||||
|
"right"
|
||||||
|
],
|
||||||
|
BlockStatement: [
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
BreakStatement: [
|
||||||
|
"label"
|
||||||
|
],
|
||||||
|
CallExpression: [
|
||||||
|
"callee",
|
||||||
|
"arguments"
|
||||||
|
],
|
||||||
|
CatchClause: [
|
||||||
|
"param",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ChainExpression: [
|
||||||
|
"expression"
|
||||||
|
],
|
||||||
|
ClassBody: [
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ClassDeclaration: [
|
||||||
|
"id",
|
||||||
|
"superClass",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ClassExpression: [
|
||||||
|
"id",
|
||||||
|
"superClass",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ConditionalExpression: [
|
||||||
|
"test",
|
||||||
|
"consequent",
|
||||||
|
"alternate"
|
||||||
|
],
|
||||||
|
ContinueStatement: [
|
||||||
|
"label"
|
||||||
|
],
|
||||||
|
DebuggerStatement: [],
|
||||||
|
DoWhileStatement: [
|
||||||
|
"body",
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
EmptyStatement: [],
|
||||||
|
ExperimentalRestProperty: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
ExperimentalSpreadProperty: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
ExportAllDeclaration: [
|
||||||
|
"exported",
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
ExportDefaultDeclaration: [
|
||||||
|
"declaration"
|
||||||
|
],
|
||||||
|
ExportNamedDeclaration: [
|
||||||
|
"declaration",
|
||||||
|
"specifiers",
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
ExportSpecifier: [
|
||||||
|
"exported",
|
||||||
|
"local"
|
||||||
|
],
|
||||||
|
ExpressionStatement: [
|
||||||
|
"expression"
|
||||||
|
],
|
||||||
|
ForInStatement: [
|
||||||
|
"left",
|
||||||
|
"right",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ForOfStatement: [
|
||||||
|
"left",
|
||||||
|
"right",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ForStatement: [
|
||||||
|
"init",
|
||||||
|
"test",
|
||||||
|
"update",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
FunctionDeclaration: [
|
||||||
|
"id",
|
||||||
|
"params",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
FunctionExpression: [
|
||||||
|
"id",
|
||||||
|
"params",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
Identifier: [],
|
||||||
|
IfStatement: [
|
||||||
|
"test",
|
||||||
|
"consequent",
|
||||||
|
"alternate"
|
||||||
|
],
|
||||||
|
ImportDeclaration: [
|
||||||
|
"specifiers",
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
ImportDefaultSpecifier: [
|
||||||
|
"local"
|
||||||
|
],
|
||||||
|
ImportExpression: [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
ImportNamespaceSpecifier: [
|
||||||
|
"local"
|
||||||
|
],
|
||||||
|
ImportSpecifier: [
|
||||||
|
"imported",
|
||||||
|
"local"
|
||||||
|
],
|
||||||
|
JSXAttribute: [
|
||||||
|
"name",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
JSXClosingElement: [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
JSXClosingFragment: [],
|
||||||
|
JSXElement: [
|
||||||
|
"openingElement",
|
||||||
|
"children",
|
||||||
|
"closingElement"
|
||||||
|
],
|
||||||
|
JSXEmptyExpression: [],
|
||||||
|
JSXExpressionContainer: [
|
||||||
|
"expression"
|
||||||
|
],
|
||||||
|
JSXFragment: [
|
||||||
|
"openingFragment",
|
||||||
|
"children",
|
||||||
|
"closingFragment"
|
||||||
|
],
|
||||||
|
JSXIdentifier: [],
|
||||||
|
JSXMemberExpression: [
|
||||||
|
"object",
|
||||||
|
"property"
|
||||||
|
],
|
||||||
|
JSXNamespacedName: [
|
||||||
|
"namespace",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
JSXOpeningElement: [
|
||||||
|
"name",
|
||||||
|
"attributes"
|
||||||
|
],
|
||||||
|
JSXOpeningFragment: [],
|
||||||
|
JSXSpreadAttribute: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
JSXSpreadChild: [
|
||||||
|
"expression"
|
||||||
|
],
|
||||||
|
JSXText: [],
|
||||||
|
LabeledStatement: [
|
||||||
|
"label",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
Literal: [],
|
||||||
|
LogicalExpression: [
|
||||||
|
"left",
|
||||||
|
"right"
|
||||||
|
],
|
||||||
|
MemberExpression: [
|
||||||
|
"object",
|
||||||
|
"property"
|
||||||
|
],
|
||||||
|
MetaProperty: [
|
||||||
|
"meta",
|
||||||
|
"property"
|
||||||
|
],
|
||||||
|
MethodDefinition: [
|
||||||
|
"key",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
NewExpression: [
|
||||||
|
"callee",
|
||||||
|
"arguments"
|
||||||
|
],
|
||||||
|
ObjectExpression: [
|
||||||
|
"properties"
|
||||||
|
],
|
||||||
|
ObjectPattern: [
|
||||||
|
"properties"
|
||||||
|
],
|
||||||
|
PrivateIdentifier: [],
|
||||||
|
Program: [
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
Property: [
|
||||||
|
"key",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
PropertyDefinition: [
|
||||||
|
"key",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
RestElement: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
ReturnStatement: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
SequenceExpression: [
|
||||||
|
"expressions"
|
||||||
|
],
|
||||||
|
SpreadElement: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
StaticBlock: [
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
Super: [],
|
||||||
|
SwitchCase: [
|
||||||
|
"test",
|
||||||
|
"consequent"
|
||||||
|
],
|
||||||
|
SwitchStatement: [
|
||||||
|
"discriminant",
|
||||||
|
"cases"
|
||||||
|
],
|
||||||
|
TaggedTemplateExpression: [
|
||||||
|
"tag",
|
||||||
|
"quasi"
|
||||||
|
],
|
||||||
|
TemplateElement: [],
|
||||||
|
TemplateLiteral: [
|
||||||
|
"quasis",
|
||||||
|
"expressions"
|
||||||
|
],
|
||||||
|
ThisExpression: [],
|
||||||
|
ThrowStatement: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
TryStatement: [
|
||||||
|
"block",
|
||||||
|
"handler",
|
||||||
|
"finalizer"
|
||||||
|
],
|
||||||
|
UnaryExpression: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
UpdateExpression: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
VariableDeclaration: [
|
||||||
|
"declarations"
|
||||||
|
],
|
||||||
|
VariableDeclarator: [
|
||||||
|
"id",
|
||||||
|
"init"
|
||||||
|
],
|
||||||
|
WhileStatement: [
|
||||||
|
"test",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
WithStatement: [
|
||||||
|
"object",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
YieldExpression: [
|
||||||
|
"argument"
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Types.
|
||||||
|
const NODE_TYPES = Object.keys(KEYS);
|
||||||
|
|
||||||
|
// Freeze the keys.
|
||||||
|
for (const type of NODE_TYPES) {
|
||||||
|
Object.freeze(KEYS[type]);
|
||||||
|
}
|
||||||
|
Object.freeze(KEYS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
|
* See LICENSE file in root directory for full license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./visitor-keys.js').VisitorKeys} VisitorKeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
// List to ignore keys.
|
||||||
|
const KEY_BLACKLIST = new Set([
|
||||||
|
"parent",
|
||||||
|
"leadingComments",
|
||||||
|
"trailingComments"
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a given key should be used or not.
|
||||||
|
* @param {string} key The key to check.
|
||||||
|
* @returns {boolean} `true` if the key should be used.
|
||||||
|
*/
|
||||||
|
function filterKey(key) {
|
||||||
|
return !KEY_BLACKLIST.has(key) && key[0] !== "_";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get visitor keys of a given node.
|
||||||
|
* @param {object} node The AST node to get keys.
|
||||||
|
* @returns {readonly string[]} Visitor keys of the node.
|
||||||
|
*/
|
||||||
|
function getKeys(node) {
|
||||||
|
return Object.keys(node).filter(filterKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable valid-jsdoc rule because it reports syntax error on the type of @returns.
|
||||||
|
// eslint-disable-next-line valid-jsdoc
|
||||||
|
/**
|
||||||
|
* Make the union set with `KEYS` and given keys.
|
||||||
|
* @param {VisitorKeys} additionalKeys The additional keys.
|
||||||
|
* @returns {VisitorKeys} The union set.
|
||||||
|
*/
|
||||||
|
function unionWith(additionalKeys) {
|
||||||
|
const retv = /** @type {{
|
||||||
|
[type: string]: ReadonlyArray<string>
|
||||||
|
}} */ (Object.assign({}, KEYS));
|
||||||
|
|
||||||
|
for (const type of Object.keys(additionalKeys)) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(retv, type)) {
|
||||||
|
const keys = new Set(additionalKeys[type]);
|
||||||
|
|
||||||
|
for (const key of retv[type]) {
|
||||||
|
keys.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
retv[type] = Object.freeze(Array.from(keys));
|
||||||
|
} else {
|
||||||
|
retv[type] = Object.freeze(Array.from(additionalKeys[type]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.freeze(retv);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.KEYS = KEYS;
|
||||||
|
exports.getKeys = getKeys;
|
||||||
|
exports.unionWith = unionWith;
|
27
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.d.cts
generated
vendored
Normal file
27
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.d.cts
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
type VisitorKeys$1 = {
|
||||||
|
readonly [type: string]: readonly string[];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @typedef {{ readonly [type: string]: ReadonlyArray<string> }} VisitorKeys
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @type {VisitorKeys}
|
||||||
|
*/
|
||||||
|
declare const KEYS: VisitorKeys$1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get visitor keys of a given node.
|
||||||
|
* @param {object} node The AST node to get keys.
|
||||||
|
* @returns {readonly string[]} Visitor keys of the node.
|
||||||
|
*/
|
||||||
|
declare function getKeys(node: object): readonly string[];
|
||||||
|
/**
|
||||||
|
* Make the union set with `KEYS` and given keys.
|
||||||
|
* @param {VisitorKeys} additionalKeys The additional keys.
|
||||||
|
* @returns {VisitorKeys} The union set.
|
||||||
|
*/
|
||||||
|
declare function unionWith(additionalKeys: VisitorKeys): VisitorKeys;
|
||||||
|
|
||||||
|
type VisitorKeys = VisitorKeys$1;
|
||||||
|
|
||||||
|
export { KEYS, VisitorKeys, getKeys, unionWith };
|
16
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/index.d.ts
generated
vendored
Normal file
16
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/index.d.ts
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Get visitor keys of a given node.
|
||||||
|
* @param {object} node The AST node to get keys.
|
||||||
|
* @returns {readonly string[]} Visitor keys of the node.
|
||||||
|
*/
|
||||||
|
export function getKeys(node: object): readonly string[];
|
||||||
|
/**
|
||||||
|
* Make the union set with `KEYS` and given keys.
|
||||||
|
* @param {VisitorKeys} additionalKeys The additional keys.
|
||||||
|
* @returns {VisitorKeys} The union set.
|
||||||
|
*/
|
||||||
|
export function unionWith(additionalKeys: VisitorKeys): VisitorKeys;
|
||||||
|
export { KEYS };
|
||||||
|
export type VisitorKeys = import('./visitor-keys.js').VisitorKeys;
|
||||||
|
import KEYS from "./visitor-keys.js";
|
||||||
|
//# sourceMappingURL=index.d.ts.map
|
12
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/visitor-keys.d.ts
generated
vendored
Normal file
12
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/visitor-keys.d.ts
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export default KEYS;
|
||||||
|
export type VisitorKeys = {
|
||||||
|
readonly [type: string]: readonly string[];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @typedef {{ readonly [type: string]: ReadonlyArray<string> }} VisitorKeys
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @type {VisitorKeys}
|
||||||
|
*/
|
||||||
|
declare const KEYS: VisitorKeys;
|
||||||
|
//# sourceMappingURL=visitor-keys.d.ts.map
|
65
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/index.js
generated
vendored
Normal file
65
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/index.js
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
|
* See LICENSE file in root directory for full license.
|
||||||
|
*/
|
||||||
|
import KEYS from "./visitor-keys.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./visitor-keys.js').VisitorKeys} VisitorKeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
// List to ignore keys.
|
||||||
|
const KEY_BLACKLIST = new Set([
|
||||||
|
"parent",
|
||||||
|
"leadingComments",
|
||||||
|
"trailingComments"
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a given key should be used or not.
|
||||||
|
* @param {string} key The key to check.
|
||||||
|
* @returns {boolean} `true` if the key should be used.
|
||||||
|
*/
|
||||||
|
function filterKey(key) {
|
||||||
|
return !KEY_BLACKLIST.has(key) && key[0] !== "_";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get visitor keys of a given node.
|
||||||
|
* @param {object} node The AST node to get keys.
|
||||||
|
* @returns {readonly string[]} Visitor keys of the node.
|
||||||
|
*/
|
||||||
|
export function getKeys(node) {
|
||||||
|
return Object.keys(node).filter(filterKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable valid-jsdoc rule because it reports syntax error on the type of @returns.
|
||||||
|
// eslint-disable-next-line valid-jsdoc
|
||||||
|
/**
|
||||||
|
* Make the union set with `KEYS` and given keys.
|
||||||
|
* @param {VisitorKeys} additionalKeys The additional keys.
|
||||||
|
* @returns {VisitorKeys} The union set.
|
||||||
|
*/
|
||||||
|
export function unionWith(additionalKeys) {
|
||||||
|
const retv = /** @type {{
|
||||||
|
[type: string]: ReadonlyArray<string>
|
||||||
|
}} */ (Object.assign({}, KEYS));
|
||||||
|
|
||||||
|
for (const type of Object.keys(additionalKeys)) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(retv, type)) {
|
||||||
|
const keys = new Set(additionalKeys[type]);
|
||||||
|
|
||||||
|
for (const key of retv[type]) {
|
||||||
|
keys.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
retv[type] = Object.freeze(Array.from(keys));
|
||||||
|
} else {
|
||||||
|
retv[type] = Object.freeze(Array.from(additionalKeys[type]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.freeze(retv);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { KEYS };
|
315
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/visitor-keys.js
generated
vendored
Normal file
315
node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/visitor-keys.js
generated
vendored
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
/**
|
||||||
|
* @typedef {{ readonly [type: string]: ReadonlyArray<string> }} VisitorKeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {VisitorKeys}
|
||||||
|
*/
|
||||||
|
const KEYS = {
|
||||||
|
ArrayExpression: [
|
||||||
|
"elements"
|
||||||
|
],
|
||||||
|
ArrayPattern: [
|
||||||
|
"elements"
|
||||||
|
],
|
||||||
|
ArrowFunctionExpression: [
|
||||||
|
"params",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
AssignmentExpression: [
|
||||||
|
"left",
|
||||||
|
"right"
|
||||||
|
],
|
||||||
|
AssignmentPattern: [
|
||||||
|
"left",
|
||||||
|
"right"
|
||||||
|
],
|
||||||
|
AwaitExpression: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
BinaryExpression: [
|
||||||
|
"left",
|
||||||
|
"right"
|
||||||
|
],
|
||||||
|
BlockStatement: [
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
BreakStatement: [
|
||||||
|
"label"
|
||||||
|
],
|
||||||
|
CallExpression: [
|
||||||
|
"callee",
|
||||||
|
"arguments"
|
||||||
|
],
|
||||||
|
CatchClause: [
|
||||||
|
"param",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ChainExpression: [
|
||||||
|
"expression"
|
||||||
|
],
|
||||||
|
ClassBody: [
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ClassDeclaration: [
|
||||||
|
"id",
|
||||||
|
"superClass",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ClassExpression: [
|
||||||
|
"id",
|
||||||
|
"superClass",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ConditionalExpression: [
|
||||||
|
"test",
|
||||||
|
"consequent",
|
||||||
|
"alternate"
|
||||||
|
],
|
||||||
|
ContinueStatement: [
|
||||||
|
"label"
|
||||||
|
],
|
||||||
|
DebuggerStatement: [],
|
||||||
|
DoWhileStatement: [
|
||||||
|
"body",
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
EmptyStatement: [],
|
||||||
|
ExperimentalRestProperty: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
ExperimentalSpreadProperty: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
ExportAllDeclaration: [
|
||||||
|
"exported",
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
ExportDefaultDeclaration: [
|
||||||
|
"declaration"
|
||||||
|
],
|
||||||
|
ExportNamedDeclaration: [
|
||||||
|
"declaration",
|
||||||
|
"specifiers",
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
ExportSpecifier: [
|
||||||
|
"exported",
|
||||||
|
"local"
|
||||||
|
],
|
||||||
|
ExpressionStatement: [
|
||||||
|
"expression"
|
||||||
|
],
|
||||||
|
ForInStatement: [
|
||||||
|
"left",
|
||||||
|
"right",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ForOfStatement: [
|
||||||
|
"left",
|
||||||
|
"right",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
ForStatement: [
|
||||||
|
"init",
|
||||||
|
"test",
|
||||||
|
"update",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
FunctionDeclaration: [
|
||||||
|
"id",
|
||||||
|
"params",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
FunctionExpression: [
|
||||||
|
"id",
|
||||||
|
"params",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
Identifier: [],
|
||||||
|
IfStatement: [
|
||||||
|
"test",
|
||||||
|
"consequent",
|
||||||
|
"alternate"
|
||||||
|
],
|
||||||
|
ImportDeclaration: [
|
||||||
|
"specifiers",
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
ImportDefaultSpecifier: [
|
||||||
|
"local"
|
||||||
|
],
|
||||||
|
ImportExpression: [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
ImportNamespaceSpecifier: [
|
||||||
|
"local"
|
||||||
|
],
|
||||||
|
ImportSpecifier: [
|
||||||
|
"imported",
|
||||||
|
"local"
|
||||||
|
],
|
||||||
|
JSXAttribute: [
|
||||||
|
"name",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
JSXClosingElement: [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
JSXClosingFragment: [],
|
||||||
|
JSXElement: [
|
||||||
|
"openingElement",
|
||||||
|
"children",
|
||||||
|
"closingElement"
|
||||||
|
],
|
||||||
|
JSXEmptyExpression: [],
|
||||||
|
JSXExpressionContainer: [
|
||||||
|
"expression"
|
||||||
|
],
|
||||||
|
JSXFragment: [
|
||||||
|
"openingFragment",
|
||||||
|
"children",
|
||||||
|
"closingFragment"
|
||||||
|
],
|
||||||
|
JSXIdentifier: [],
|
||||||
|
JSXMemberExpression: [
|
||||||
|
"object",
|
||||||
|
"property"
|
||||||
|
],
|
||||||
|
JSXNamespacedName: [
|
||||||
|
"namespace",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
JSXOpeningElement: [
|
||||||
|
"name",
|
||||||
|
"attributes"
|
||||||
|
],
|
||||||
|
JSXOpeningFragment: [],
|
||||||
|
JSXSpreadAttribute: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
JSXSpreadChild: [
|
||||||
|
"expression"
|
||||||
|
],
|
||||||
|
JSXText: [],
|
||||||
|
LabeledStatement: [
|
||||||
|
"label",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
Literal: [],
|
||||||
|
LogicalExpression: [
|
||||||
|
"left",
|
||||||
|
"right"
|
||||||
|
],
|
||||||
|
MemberExpression: [
|
||||||
|
"object",
|
||||||
|
"property"
|
||||||
|
],
|
||||||
|
MetaProperty: [
|
||||||
|
"meta",
|
||||||
|
"property"
|
||||||
|
],
|
||||||
|
MethodDefinition: [
|
||||||
|
"key",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
NewExpression: [
|
||||||
|
"callee",
|
||||||
|
"arguments"
|
||||||
|
],
|
||||||
|
ObjectExpression: [
|
||||||
|
"properties"
|
||||||
|
],
|
||||||
|
ObjectPattern: [
|
||||||
|
"properties"
|
||||||
|
],
|
||||||
|
PrivateIdentifier: [],
|
||||||
|
Program: [
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
Property: [
|
||||||
|
"key",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
PropertyDefinition: [
|
||||||
|
"key",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
RestElement: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
ReturnStatement: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
SequenceExpression: [
|
||||||
|
"expressions"
|
||||||
|
],
|
||||||
|
SpreadElement: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
StaticBlock: [
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
Super: [],
|
||||||
|
SwitchCase: [
|
||||||
|
"test",
|
||||||
|
"consequent"
|
||||||
|
],
|
||||||
|
SwitchStatement: [
|
||||||
|
"discriminant",
|
||||||
|
"cases"
|
||||||
|
],
|
||||||
|
TaggedTemplateExpression: [
|
||||||
|
"tag",
|
||||||
|
"quasi"
|
||||||
|
],
|
||||||
|
TemplateElement: [],
|
||||||
|
TemplateLiteral: [
|
||||||
|
"quasis",
|
||||||
|
"expressions"
|
||||||
|
],
|
||||||
|
ThisExpression: [],
|
||||||
|
ThrowStatement: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
TryStatement: [
|
||||||
|
"block",
|
||||||
|
"handler",
|
||||||
|
"finalizer"
|
||||||
|
],
|
||||||
|
UnaryExpression: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
UpdateExpression: [
|
||||||
|
"argument"
|
||||||
|
],
|
||||||
|
VariableDeclaration: [
|
||||||
|
"declarations"
|
||||||
|
],
|
||||||
|
VariableDeclarator: [
|
||||||
|
"id",
|
||||||
|
"init"
|
||||||
|
],
|
||||||
|
WhileStatement: [
|
||||||
|
"test",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
WithStatement: [
|
||||||
|
"object",
|
||||||
|
"body"
|
||||||
|
],
|
||||||
|
YieldExpression: [
|
||||||
|
"argument"
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Types.
|
||||||
|
const NODE_TYPES = Object.keys(KEYS);
|
||||||
|
|
||||||
|
// Freeze the keys.
|
||||||
|
for (const type of NODE_TYPES) {
|
||||||
|
Object.freeze(KEYS[type]);
|
||||||
|
}
|
||||||
|
Object.freeze(KEYS);
|
||||||
|
|
||||||
|
export default KEYS;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user