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