upwwwards 0.1.10-beta.1 → 0.1.12-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -103,10 +103,16 @@ declare abstract class Classter {
103
103
  */
104
104
  static [run](_class: string | number | bigint | boolean | RegExp | null | undefined, id: string): void;
105
105
  /**
106
- * Walks ESTree object properties: either push keys as class tokens, or follow class-identifier values.
107
- * Recurses into nested `ObjectExpression` spreads.
106
+ * Walks ESTree object properties.
107
+ * - `checkKey === true` (e.g. Vue/Svelte `:class` / `class={…}` object maps): register keys as class tokens.
108
+ Identifier keys are pushed as-is; string `Literal` keys (e.g. `'pa:1rem'`) and other key expressions go through
109
+ `run` / `check` so quoted Classter tokens inside arrays/objects are found.
110
+ * - `checkKey === false` (e.g. `v-bind` / spreads / attribute bags): follow values whose key is in
111
+ {@link Classter.CLASS_IDENTIFIERS}; if the key is in {@link Classter.ATTRIBUTES_IDENTIFIERS} and the value is an
112
+ `ObjectExpression`, recurse (nested `attrs` / `propAttrs` bags).
113
+ * Also recurses into object spreads (`…{ … }`).
108
114
  * @param props Object properties (and spreads).
109
- * @param checkKey When `true`, treat property keys as class tokens; otherwise resolve class-identifier values.
115
+ * @param checkKey When `true`, treat property keys as class tokens; otherwise resolve class / attribute-identifier values.
110
116
  * @param id Source file id for warnings.
111
117
  * @internal
112
118
  */
@@ -223,10 +223,16 @@ class Classter {
223
223
  for (let i = 0, max = CLASSES.length; i < max; i++) Classter[push](CLASSES[i], id);
224
224
  }
225
225
  /**
226
- * Walks ESTree object properties: either push keys as class tokens, or follow class-identifier values.
227
- * Recurses into nested `ObjectExpression` spreads.
226
+ * Walks ESTree object properties.
227
+ * - `checkKey === true` (e.g. Vue/Svelte `:class` / `class={…}` object maps): register keys as class tokens.
228
+ Identifier keys are pushed as-is; string `Literal` keys (e.g. `'pa:1rem'`) and other key expressions go through
229
+ `run` / `check` so quoted Classter tokens inside arrays/objects are found.
230
+ * - `checkKey === false` (e.g. `v-bind` / spreads / attribute bags): follow values whose key is in
231
+ {@link Classter.CLASS_IDENTIFIERS}; if the key is in {@link Classter.ATTRIBUTES_IDENTIFIERS} and the value is an
232
+ `ObjectExpression`, recurse (nested `attrs` / `propAttrs` bags).
233
+ * Also recurses into object spreads (`…{ … }`).
228
234
  * @param props Object properties (and spreads).
229
- * @param checkKey When `true`, treat property keys as class tokens; otherwise resolve class-identifier values.
235
+ * @param checkKey When `true`, treat property keys as class tokens; otherwise resolve class / attribute-identifier values.
230
236
  * @param id Source file id for warnings.
231
237
  * @internal
232
238
  */
@@ -234,9 +240,15 @@ class Classter {
234
240
  for (let i = 0, max = props.length; i < max; i++) {
235
241
  const PROP = props[i];
236
242
  if (PROP.type === "Property") {
237
- if ("name" in PROP.key) {
238
- if (checkKey) Classter[push](PROP.key.name, id);
239
- else if (Classter.CLASS_IDENTIFIERS.includes(PROP.key.name.toLowerCase())) Classter[check](PROP.value, false, id);
243
+ if (checkKey) {
244
+ if (PROP.key.type === "Identifier") Classter[push](PROP.key.name, id);
245
+ else if (PROP.key.type === "Literal") Classter[run](PROP.key.value, id);
246
+ else Classter[check](PROP.key, false, id);
247
+ } else {
248
+ const KEY = PROP.key.type === "Identifier" ? PROP.key.name.toLowerCase() : PROP.key.type === "Literal" && typeof PROP.key.value === "string" ? PROP.key.value.toLowerCase() : null;
249
+ if (!KEY) continue;
250
+ if (Classter.CLASS_IDENTIFIERS.includes(KEY)) Classter[check](PROP.value, false, id);
251
+ else if (Classter.ATTRIBUTES_IDENTIFIERS.includes(KEY) && PROP.value.type === "ObjectExpression") Classter[runProperties](PROP.value.properties, false, id);
240
252
  }
241
253
  } else if (PROP.argument.type === "ObjectExpression") Classter[runProperties](PROP.argument.properties, checkKey, id);
242
254
  }
@@ -347,7 +359,7 @@ class Classter {
347
359
  case /* ?{var} */
348
360
  "Identifier":
349
361
  // Logs.log((Svelte.#__CURRENT_AST?.instance?.content.body?.[0] as any)?.declarations)
350
- // TODO: gérer le cas des variables en parcourant le body (voir tout les cas possible)
362
+ // TODO: Handle the case of variables when iterating through the body (consider all possible cases)
351
363
  case /* ?Object[key] */
352
364
  "MemberExpression":
353
365
  break;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/classter/@/Classter.ts"],"sourcesContent":["/* [Classter] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SCRIPTS\r\nimport Strings from '../../scripts/Strings.js'\r\nimport Logs from '../../scripts/Logs.js'\r\n\r\nimport PROPS from './@classter/props.js'\r\n\r\n // ##TYPES\r\nimport type { Expression, PrivateIdentifier, Pattern, SpreadElement, Property } from 'estree'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Classter\r\n{\r\n /**\r\n * Attribute / prop name scanned for class tokens (e.g. `\"class\"`, or a custom name such as `\"innerClass\"`).\r\n */\r\n export type IDENTIFIER = string\r\n}\r\n\r\n// #CONSTANTS\r\n\r\n // ##SYMBOLS\r\nconst\r\nrun = Symbol('run'),\r\nrunProperties = Symbol('runProperties'),\r\npush = Symbol('push'),\r\ncheck = Symbol('check')\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Base of Classter, the optional atomic-CSS generator, shared by the framework analyzers\r\n * `Vue` (`upwwwards/classter/Vue`) and `Svelte` (`upwwwards/classter/Svelte`).\r\n *\r\n * Templates and HTML are scanned for class tokens shaped `alias:value`, `alias:[value]` or `alias:value:pseudo`:\r\n * - `alias` is a shortcut of a CSS property (`pa` for `padding`, `ba-co` for `background-color`, see `props`; extend with {@link Classter.addAlias}).\r\n * - a bracketed value may also contain `:` or `[`, and `_` stands for a space (`ma:[0_auto]` gives `margin:0 auto`).\r\n * - `pseudo` is `:before` or `:after` (`co:[#fff]:before`).\r\n *\r\n * Each valid token becomes one CSS rule, collected into the stylesheet returned by {@link Classter.get}.\r\n * The Vite plugin serves it as the virtual module `classter.css`. All state is static and shared by the subclasses.\r\n*/\r\nabstract class Classter\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n /**\r\n * Attribute names whose values are class lists.\r\n */\r\n static #CLASS_IDENTIFIERS: Classter.IDENTIFIER[] = ['class']\r\n /**\r\n * Attribute names whose object values may contain class identifiers.\r\n */\r\n static #ATTRIBUTES_IDENTIFIERS: Classter.IDENTIFIER[] = [] // *ID of objects to read (may contain class properties; example of a prop in Svelte: propAttributes={{ class: 'read this' }})\r\n\r\n /**\r\n * Registered tokens: class name to `[declaration, pseudo-element selector]`.\r\n */\r\n static #MAP = new Map<string, [expression: string, pseudoClass: string]>()\r\n\r\n static #RGX_KEY = /^@?[a-z-]+$/\r\n static #RGX_PROP = /^@?[\\w-]+$/\r\n static #RGX_SPLIT = /\\s+/g\r\n static #RGX_CLASS_ATTRIBUTE = /class=\"([^\"]*)\"/g\r\n static #RGX_ANALYZE = /^(@?[a-z-]+):(?:([^:\\s[\\\\]+)|\\[([^\\s\\\\]+)\\])(:[a-z]+)?$/\r\n static #RGX_EXPRESSION_PARSING = /_+/g\r\n static #RGX_QUOTE_PARSING = /\"|'|`/g\r\n static #RGX_COMMENT = /\\/\\*|\\*\\//\r\n static #RGX_ESCAPE = /([!#$%&()*+,./:;<=>?@[\\\\\\]^{|}~])/g\r\n\r\n // *By using getters and setters, we can be sure that the values are shared across the inheritance hierarchy (otherwise, each class would have its own value)\r\n static #updated = false\r\n static #warn = true\r\n\r\n static #ext = ''\r\n\r\n // ##PRIVATES\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n /**\r\n * Sets the \"stylesheet changed\" flag; the Vite plugin resets it to `false` after reloading `classter.css`.\r\n * Shared across the inheritance hierarchy.\r\n * @internal\r\n */\r\n static set updated(b: boolean) { Classter.#updated = b }\r\n /**\r\n * Enables / disables warnings about unknown aliases and expressions that cannot be analyzed statically.\r\n * Set to `false` by the `silent` option of the Vite plugin. Shared across the inheritance hierarchy.\r\n */\r\n static set warn(b: boolean) { Classter.#warn = b }\r\n\r\n /**\r\n * Sets the component file extension (`.vue` / `.svelte`) whose files are passed to `analyze`; set by the Vite plugin from the adapter.\r\n * Shared across the inheritance hierarchy.\r\n * @internal\r\n */\r\n static set ext(s: string) { Classter.#ext = s }\r\n\r\n // ##GETTER\r\n /**\r\n * Attribute names whose values are scanned as class lists: `\"class\"` plus names added with {@link Classter.addClassIdentifiers}.\r\n */\r\n static get CLASS_IDENTIFIERS(): Classter.IDENTIFIER[] { return Classter.#CLASS_IDENTIFIERS }\r\n /**\r\n * Attribute names whose object-literal values are scanned for class identifiers (added with {@link Classter.addAttributesIdentifiers}).\r\n */\r\n static get ATTRIBUTES_IDENTIFIERS(): Classter.IDENTIFIER[] { return Classter.#ATTRIBUTES_IDENTIFIERS }\r\n\r\n /**\r\n * `true` when at least one new rule was registered since the flag was last reset.\r\n */\r\n static get updated(): boolean { return Classter.#updated }\r\n /**\r\n * Whether warnings about unknown aliases and expressions that cannot be analyzed statically are logged. Default `true`.\r\n */\r\n static get warn(): boolean { return Classter.#warn }\r\n\r\n /**\r\n * Component file extension (`.vue` / `.svelte`) whose files are passed to `analyze`; empty until set by the Vite plugin.\r\n */\r\n static get ext(): string { return Classter.#ext }\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n\r\n // ##GET\r\n /**\r\n * Builds the stylesheet from every registered token: one rule per token, with the token escaped as class selector\r\n * (e.g. `.pa\\:1rem{padding:1rem}`).\r\n * @returns Concatenated CSS rules, or an empty string when no token is registered.\r\n */\r\n static get(): string\r\n {\r\n let _class = ''\r\n \r\n for (const [CLASS, [EXPRESSION, PSEUDO_CLASS]] of Classter.#MAP) _class += `.${CLASS.replace(Classter.#RGX_ESCAPE, '\\\\$1').replace(Classter.#RGX_QUOTE_PARSING, '\\\\27')}${PSEUDO_CLASS}{${EXPRESSION}}`\r\n\r\n return _class\r\n }\r\n\r\n // ##ADD\r\n /**\r\n * Appends the lowercase and kebab-case forms of `identifier` to `identifiers`, skipping duplicates.\r\n * @param identifiers Target list (`CLASS_IDENTIFIERS` or `ATTRIBUTES_IDENTIFIERS`).\r\n * @param identifier Raw name to normalize and append.\r\n */\r\n static #add(identifiers: Classter.IDENTIFIER[], identifier: Classter.IDENTIFIER): void\r\n {\r\n const\r\n LOWER = identifier.toLowerCase(),\r\n KEBAB = Strings.kebab(identifier)\r\n\r\n if (!identifiers.includes(LOWER)) identifiers.push(LOWER)\r\n if (!identifiers.includes(KEBAB)) identifiers.push(KEBAB)\r\n }\r\n\r\n /**\r\n * Adds attribute / prop names whose values are scanned as class lists, in addition to `class`.\r\n * Usually set through `classter.identifiers.class` of the Vite plugin.\r\n * @param identifiers Names to add (each stored in lowercase and kebab-case, e.g. `innerClass` gives `innerclass` and `inner-class`).\r\n */\r\n static addClassIdentifiers(identifiers: Classter.IDENTIFIER[]): void { for (let i = 0, max = identifiers.length; i < max; i++) Classter.#add(Classter.#CLASS_IDENTIFIERS, identifiers[i]) }\r\n\r\n /**\r\n * Adds attribute / prop names whose object-literal values are scanned for class identifiers\r\n * (e.g. `attrs` for `attrs={{ class: 'pa:1rem' }}`). Usually set through `classter.identifiers.attributes` of the Vite plugin.\r\n * @param identifiers Names to add (each stored in lowercase and kebab-case).\r\n */\r\n static addAttributesIdentifiers(identifiers: Classter.IDENTIFIER[]): void { for (let i = 0, max = identifiers.length; i < max; i++) Classter.#add(Classter.#ATTRIBUTES_IDENTIFIERS, identifiers[i]) }\r\n\r\n /**\r\n * Registers custom aliases, each mapping a shortcut to a CSS property, on the shared alias table.\r\n * Usually set through `classter.alias` of the Vite plugin.\r\n * Logs a warning and skips the entry when the key is not lowercase letters / hyphens (optionally prefixed with `@`),\r\n * when the key is already used, or when the property is not a valid name (letters, digits, `_`, `-`).\r\n * @param alias Map of shortcut keys to CSS property names.\r\n * @example\r\n * ```ts\r\n * import Vue from 'upwwwards/classter/Vue'\r\n *\r\n * Vue.addAlias({ 'my-pa': 'padding', 'ac-co': 'accent-color' }) // 'ac-co' is already defined: warns and is skipped\r\n *\r\n * // <div class=\"my-pa:1rem\"> now generates .my-pa\\:1rem{padding:1rem}\r\n * ```\r\n */\r\n static addAlias(alias: Record<string, string>): void\r\n {\r\n for (const KEY in alias) switch (true)\r\n {\r\n case !Classter.#RGX_KEY.test(KEY):\r\n Logs.warn('CLASSTER', `KEY \"${KEY}\" IS INVALID.`)\r\n continue\r\n case KEY in PROPS:\r\n Logs.warn('CLASSTER', `KEY \"${KEY}\" IS ALREADY IN USE.`)\r\n continue\r\n default:\r\n const PROP = alias[KEY]\r\n\r\n Classter.#RGX_PROP.test(PROP)\r\n ? PROPS[KEY] = PROP\r\n : Logs.warn('CLASSTER', `THE \"${PROP}\" PROPERTY MUST BE A VALID CSS PROPERTY.`)\r\n }\r\n }\r\n\r\n // ##IS\r\n // static #isSpace(char: string): char is ' ' | '\\t' | '\\n' | '\\r' | '\\f'\r\n // {\r\n // switch (char)\r\n // {\r\n // case ' ' :\r\n // case '\\t':\r\n // case '\\n':\r\n // case '\\r':\r\n // case '\\f': return true\r\n // default : return false\r\n // }\r\n // }\r\n\r\n /**\r\n * Validates a CSS value string: rejects empty values, comments, unbalanced brackets / parens,\r\n * and bare `{` `}` `;` outside quotes.\r\n * @param value Candidate declaration value (already space-normalized from `[…]` tokens).\r\n * @returns `true` when the value is considered safe to emit.\r\n */\r\n static #isValidValue(value: string): boolean\r\n {\r\n if (!value || Classter.#RGX_COMMENT.test(value)) return false\r\n\r\n const STACK = Array(8)\r\n\r\n let\r\n p = 0,\r\n quote = false\r\n\r\n for (let i = 0, max = value.length; i < max; i++)\r\n {\r\n if (quote)\r\n {\r\n const CHAR = value[i]\r\n\r\n if ((CHAR === '\"' || CHAR === '\\'')) quote = false\r\n }\r\n else switch (value[i])\r\n {\r\n case '{':\r\n case '}':\r\n case ';': return false\r\n case '[':\r\n STACK[p++] = 0\r\n break\r\n case ']':\r\n if (STACK[--p] !== 0) return false\r\n break\r\n case '(':\r\n STACK[p++] = 1\r\n break\r\n case ')':\r\n if (STACK[--p] !== 1) return false\r\n break\r\n case '\"' :\r\n case '\\'':\r\n quote = true\r\n break\r\n default:\r\n }\r\n }\r\n \r\n return !p && !quote\r\n }\r\n\r\n // ##RUNNERS\r\n /**\r\n * Splits a whitespace-separated class string and registers each token; falsy values are ignored.\r\n * @param _class Class attribute content (coerced via `toString`).\r\n * @param id Source file id for warnings.\r\n * @internal\r\n */\r\n static [run](_class: string | number | bigint | boolean | RegExp | null | undefined, id: string): void\r\n {\r\n if (!_class) return\r\n\r\n const CLASSES = _class.toString().trim().split(Classter.#RGX_SPLIT)\r\n\r\n for (let i = 0, max = CLASSES.length; i < max; i++) Classter[push](CLASSES[i], id)\r\n }\r\n\r\n /**\r\n * Walks ESTree object properties: either push keys as class tokens, or follow class-identifier values.\r\n * Recurses into nested `ObjectExpression` spreads.\r\n * @param props Object properties (and spreads).\r\n * @param checkKey When `true`, treat property keys as class tokens; otherwise resolve class-identifier values.\r\n * @param id Source file id for warnings.\r\n * @internal\r\n */\r\n static [runProperties](props: (Property | SpreadElement)[], checkKey: boolean, id: string): void\r\n {\r\n for (let i = 0, max = props.length; i < max; i++)\r\n {\r\n const PROP = props[i]\r\n\r\n if (PROP.type === 'Property')\r\n {\r\n if ('name' in PROP.key)\r\n {\r\n if (checkKey) Classter[push](PROP.key.name, id)\r\n else if (Classter.CLASS_IDENTIFIERS.includes(PROP.key.name.toLowerCase())) Classter[check](PROP.value, false, id)\r\n }\r\n }\r\n else if (PROP.argument.type === 'ObjectExpression') Classter[runProperties](PROP.argument.properties, checkKey, id)\r\n }\r\n }\r\n\r\n /**\r\n * Runs `check` on each array element (unwraps `SpreadElement`).\r\n * @param els Array expression elements.\r\n * @param toString When `true`, object keys are not treated as classes (string-like evaluation).\r\n * @param id Source file id for warnings.\r\n */\r\n static #runElements(els: (Expression | SpreadElement | null)[], toString: boolean, id: string): void\r\n {\r\n for (let i = 0, max = els.length; i < max; i++)\r\n {\r\n const EL = els[i]\r\n\r\n if (EL) Classter[check](EL.type === 'SpreadElement' ? EL.argument : EL, toString, id)\r\n }\r\n }\r\n\r\n /**\r\n * Runs `check` on each expression in a list.\r\n * @param exprs Expressions to walk.\r\n * @param toString When `true`, object keys are not treated as classes.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runExpressions(exprs: Expression[], toString: boolean, id: string): void { for (let i = 0, max = exprs.length; i < max; i++) Classter[check](exprs[i], toString, id) }\r\n\r\n // ##ANALYZERS\r\n /**\r\n * Analyzes a component source file and registers the class tokens it contains.\r\n * Base implementation does nothing; overridden by `Vue` and `Svelte`. Called by the Vite plugin on transform.\r\n * @param code Source file contents.\r\n * @param id Source file id, used in warnings.\r\n */\r\n static analyze(code: string, id: string): void {}\r\n\r\n /**\r\n * Analyzes raw HTML with a lightweight scan: only double-quoted `class=\"...\"` attributes are read\r\n * (custom class identifiers are ignored).\r\n * @param code Raw HTML / markup string.\r\n * @param id Source file id, used in warnings.\r\n */\r\n static analyzeHTML(code: string, id: string): void\r\n {\r\n let r\r\n\r\n while (r = Classter.#RGX_CLASS_ATTRIBUTE.exec(code)) Classter[run](r[1], id)\r\n }\r\n\r\n // ##UTILS\r\n /**\r\n * Registers one token: parses `alias:value[:pseudo]`, resolves the alias, validates the value and pseudo-element,\r\n * and stores the declaration (sets `updated` on first insert). Tokens not shaped like `alias:value` are ignored silently.\r\n * @param _class Single class token (e.g. `pa:1rem` or `co:[#fff]:before`).\r\n * @param id Source file id for unknown-alias warnings.\r\n * @internal\r\n */\r\n static [push](_class: string, id: string): void\r\n {\r\n const MATCH = _class.match(Classter.#RGX_ANALYZE)\r\n\r\n if (!MATCH) return\r\n\r\n const PROP = PROPS[MATCH[1]]\r\n\r\n if (PROP)\r\n {\r\n const VALUE = MATCH[2] || MATCH[3]?.replace(Classter.#RGX_EXPRESSION_PARSING, ' ').trim()\r\n\r\n if (!Classter.#isValidValue(VALUE)) return Logs.warn('CLASSTER', `THE VALUE IN CLASS \"${_class}\" IS INCORRECT.`)\r\n\r\n const PC = MATCH[4]\r\n\r\n if (PC && !(PC in PROPS)) return Logs.warn('CLASSTER', `PSEUDO-CLASS \"${PC}\" IS NOT SUPPORTED.`)\r\n if (Classter.#MAP.has(_class)) return\r\n\r\n Classter.#MAP.set(_class, [`${PROP}:${VALUE.replace(Classter.#RGX_QUOTE_PARSING, '\"')}`, PC ? PROPS[PC] : ''])\r\n\r\n Classter.updated ||= true\r\n }\r\n else if (Classter.warn) Logs.warn('CLASSTER', `THE ALIAS \"${MATCH[1]}\" IN CLASS \"${_class}\" OF FILE \"${id}\" DOES NOT EXIST.`)\r\n }\r\n\r\n /**\r\n * Walks an ESTree expression and extracts class tokens where statically knowable.\r\n * Supports arrays, `+` of literals, logical / conditional, literals, templates, and objects.\r\n * Identifiers and member expressions are intentionally skipped (runtime values).\r\n * @param expression ESTree node to inspect.\r\n * @param toString When `true`, mimic string coercion (objects not expanded as class maps; arrays with length ≠ 1 skipped).\r\n * @param id Source file id for warnings.\r\n * @internal\r\n */\r\n static [check](expression: Expression | PrivateIdentifier | Pattern, toString: boolean, id: string): void\r\n {\r\n switch (expression.type)\r\n {\r\n case /* ?[x] */ 'ArrayExpression':\r\n if (!toString || expression.elements.length === 1) Classter.#runElements(expression.elements, toString, id)\r\n break\r\n case /* ?x + y */ 'BinaryExpression':\r\n if (expression.operator === '+')\r\n {\r\n if (expression.left.type === 'Literal' && expression.right.type === 'Literal') Classter[run]('' + expression.left.value + expression.right.value, id)\r\n else if (Classter.warn) Logs.warn('CLASSTER', 'UNABLE TO DEDUCE THE EXPRESSION:', expression, 'IN FILE:', id)\r\n }\r\n\r\n break\r\n case /* ?x || y */ 'LogicalExpression':\r\n Classter[check](expression.left, toString, id)\r\n Classter[check](expression.right, toString, id)\r\n break\r\n case /* ?boolean ? x : y */ 'ConditionalExpression':\r\n Classter[check](expression.consequent, toString, id)\r\n Classter[check](expression.alternate, toString, id)\r\n break\r\n case /* ?x */ 'Literal':\r\n Classter[run](expression.value, id)\r\n break\r\n case /* ?`x ${y}` */ 'TemplateLiteral':\r\n for (let i = 0, max = expression.quasis.length; i < max; i++) Classter[run](expression.quasis[i].value.cooked, id)\r\n \r\n Classter.#runExpressions(expression.expressions, toString, id)\r\n \r\n break\r\n case /* ?{var} */ 'Identifier' : // Logs.log((Svelte.#__CURRENT_AST?.instance?.content.body?.[0] as any)?.declarations)\r\n // TODO: gérer le cas des variables en parcourant le body (voir tout les cas possible)\r\n case /* ?Object[key] */ 'MemberExpression': break\r\n case /* ?{ x: y } */ 'ObjectExpression':\r\n if (!toString) Classter[runProperties](expression.properties, true, id)\r\n break\r\n default: if (Classter.warn) Logs.warn('CLASSTER', `THE EXPRESSION \"${expression.type}\" IS NOT CONTROLLED.`)\r\n }\r\n }\r\n\r\n // static #split(_class: string): string[]\r\n // {\r\n // const CLASSES: string[] = []\r\n\r\n // let\r\n // a = -1,\r\n // b = 0\r\n\r\n // for (let i = 0, max = _class.length; i < max; i++)\r\n // {\r\n // const CHAR = _class[i]\r\n\r\n // if (Classter.#isSpace(CHAR))\r\n // {\r\n // if (a === -1 || b > 0) continue\r\n\r\n // CLASSES.push(_class.substring(a, i))\r\n\r\n // a = -1\r\n // }\r\n // else\r\n // {\r\n // if (a === -1) a = i\r\n\r\n // if (CHAR === '[') b++\r\n // else if (CHAR === ']' && b) b-- \r\n // }\r\n // }\r\n\r\n // if (~a) CLASSES.push(_class.substring(a))\r\n\r\n // return CLASSES\r\n // }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Classter\r\n\r\n/**\r\n * Symbol keys of the internal scanning methods, used by the `Vue` and `Svelte` analyzers.\r\n * @internal\r\n*/\r\nexport { run, runProperties, push, check }\r\n\r\nexport type { Classter }"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/classter/@/Classter.ts"],"sourcesContent":["/* [Classter] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SCRIPTS\r\nimport Strings from '../../scripts/Strings.js'\r\nimport Logs from '../../scripts/Logs.js'\r\n\r\nimport PROPS from './@classter/props.js'\r\n\r\n // ##TYPES\r\nimport type { Expression, PrivateIdentifier, Pattern, SpreadElement, Property } from 'estree'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Classter\r\n{\r\n /**\r\n * Attribute / prop name scanned for class tokens (e.g. `\"class\"`, or a custom name such as `\"innerClass\"`).\r\n */\r\n export type IDENTIFIER = string\r\n}\r\n\r\n// #CONSTANTS\r\n\r\n // ##SYMBOLS\r\nconst\r\nrun = Symbol('run'),\r\nrunProperties = Symbol('runProperties'),\r\npush = Symbol('push'),\r\ncheck = Symbol('check')\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Base of Classter, the optional atomic-CSS generator, shared by the framework analyzers\r\n * `Vue` (`upwwwards/classter/Vue`) and `Svelte` (`upwwwards/classter/Svelte`).\r\n *\r\n * Templates and HTML are scanned for class tokens shaped `alias:value`, `alias:[value]` or `alias:value:pseudo`:\r\n * - `alias` is a shortcut of a CSS property (`pa` for `padding`, `ba-co` for `background-color`, see `props`; extend with {@link Classter.addAlias}).\r\n * - a bracketed value may also contain `:` or `[`, and `_` stands for a space (`ma:[0_auto]` gives `margin:0 auto`).\r\n * - `pseudo` is `:before` or `:after` (`co:[#fff]:before`).\r\n *\r\n * Each valid token becomes one CSS rule, collected into the stylesheet returned by {@link Classter.get}.\r\n * The Vite plugin serves it as the virtual module `classter.css`. All state is static and shared by the subclasses.\r\n*/\r\nabstract class Classter\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n /**\r\n * Attribute names whose values are class lists.\r\n */\r\n static #CLASS_IDENTIFIERS: Classter.IDENTIFIER[] = ['class']\r\n /**\r\n * Attribute names whose object values may contain class identifiers.\r\n */\r\n static #ATTRIBUTES_IDENTIFIERS: Classter.IDENTIFIER[] = [] // *ID of objects to read (may contain class properties; example of a prop in Svelte: propAttributes={{ class: 'read this' }})\r\n\r\n /**\r\n * Registered tokens: class name to `[declaration, pseudo-element selector]`.\r\n */\r\n static #MAP = new Map<string, [expression: string, pseudoClass: string]>()\r\n\r\n static #RGX_KEY = /^@?[a-z-]+$/\r\n static #RGX_PROP = /^@?[\\w-]+$/\r\n static #RGX_SPLIT = /\\s+/g\r\n static #RGX_CLASS_ATTRIBUTE = /class=\"([^\"]*)\"/g\r\n static #RGX_ANALYZE = /^(@?[a-z-]+):(?:([^:\\s[\\\\]+)|\\[([^\\s\\\\]+)\\])(:[a-z]+)?$/\r\n static #RGX_EXPRESSION_PARSING = /_+/g\r\n static #RGX_QUOTE_PARSING = /\"|'|`/g\r\n static #RGX_COMMENT = /\\/\\*|\\*\\//\r\n static #RGX_ESCAPE = /([!#$%&()*+,./:;<=>?@[\\\\\\]^{|}~])/g\r\n\r\n // *By using getters and setters, we can be sure that the values are shared across the inheritance hierarchy (otherwise, each class would have its own value)\r\n static #updated = false\r\n static #warn = true\r\n\r\n static #ext = ''\r\n\r\n // ##PRIVATES\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n /**\r\n * Sets the \"stylesheet changed\" flag; the Vite plugin resets it to `false` after reloading `classter.css`.\r\n * Shared across the inheritance hierarchy.\r\n * @internal\r\n */\r\n static set updated(b: boolean) { Classter.#updated = b }\r\n /**\r\n * Enables / disables warnings about unknown aliases and expressions that cannot be analyzed statically.\r\n * Set to `false` by the `silent` option of the Vite plugin. Shared across the inheritance hierarchy.\r\n */\r\n static set warn(b: boolean) { Classter.#warn = b }\r\n\r\n /**\r\n * Sets the component file extension (`.vue` / `.svelte`) whose files are passed to `analyze`; set by the Vite plugin from the adapter.\r\n * Shared across the inheritance hierarchy.\r\n * @internal\r\n */\r\n static set ext(s: string) { Classter.#ext = s }\r\n\r\n // ##GETTER\r\n /**\r\n * Attribute names whose values are scanned as class lists: `\"class\"` plus names added with {@link Classter.addClassIdentifiers}.\r\n */\r\n static get CLASS_IDENTIFIERS(): Classter.IDENTIFIER[] { return Classter.#CLASS_IDENTIFIERS }\r\n /**\r\n * Attribute names whose object-literal values are scanned for class identifiers (added with {@link Classter.addAttributesIdentifiers}).\r\n */\r\n static get ATTRIBUTES_IDENTIFIERS(): Classter.IDENTIFIER[] { return Classter.#ATTRIBUTES_IDENTIFIERS }\r\n\r\n /**\r\n * `true` when at least one new rule was registered since the flag was last reset.\r\n */\r\n static get updated(): boolean { return Classter.#updated }\r\n /**\r\n * Whether warnings about unknown aliases and expressions that cannot be analyzed statically are logged. Default `true`.\r\n */\r\n static get warn(): boolean { return Classter.#warn }\r\n\r\n /**\r\n * Component file extension (`.vue` / `.svelte`) whose files are passed to `analyze`; empty until set by the Vite plugin.\r\n */\r\n static get ext(): string { return Classter.#ext }\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n\r\n // ##GET\r\n /**\r\n * Builds the stylesheet from every registered token: one rule per token, with the token escaped as class selector\r\n * (e.g. `.pa\\:1rem{padding:1rem}`).\r\n * @returns Concatenated CSS rules, or an empty string when no token is registered.\r\n */\r\n static get(): string\r\n {\r\n let _class = ''\r\n \r\n for (const [CLASS, [EXPRESSION, PSEUDO_CLASS]] of Classter.#MAP) _class += `.${CLASS.replace(Classter.#RGX_ESCAPE, '\\\\$1').replace(Classter.#RGX_QUOTE_PARSING, '\\\\27')}${PSEUDO_CLASS}{${EXPRESSION}}`\r\n\r\n return _class\r\n }\r\n\r\n // ##ADD\r\n /**\r\n * Appends the lowercase and kebab-case forms of `identifier` to `identifiers`, skipping duplicates.\r\n * @param identifiers Target list (`CLASS_IDENTIFIERS` or `ATTRIBUTES_IDENTIFIERS`).\r\n * @param identifier Raw name to normalize and append.\r\n */\r\n static #add(identifiers: Classter.IDENTIFIER[], identifier: Classter.IDENTIFIER): void\r\n {\r\n const\r\n LOWER = identifier.toLowerCase(),\r\n KEBAB = Strings.kebab(identifier)\r\n\r\n if (!identifiers.includes(LOWER)) identifiers.push(LOWER)\r\n if (!identifiers.includes(KEBAB)) identifiers.push(KEBAB)\r\n }\r\n\r\n /**\r\n * Adds attribute / prop names whose values are scanned as class lists, in addition to `class`.\r\n * Usually set through `classter.identifiers.class` of the Vite plugin.\r\n * @param identifiers Names to add (each stored in lowercase and kebab-case, e.g. `innerClass` gives `innerclass` and `inner-class`).\r\n */\r\n static addClassIdentifiers(identifiers: Classter.IDENTIFIER[]): void { for (let i = 0, max = identifiers.length; i < max; i++) Classter.#add(Classter.#CLASS_IDENTIFIERS, identifiers[i]) }\r\n\r\n /**\r\n * Adds attribute / prop names whose object-literal values are scanned for class identifiers\r\n * (e.g. `attrs` for `attrs={{ class: 'pa:1rem' }}`). Usually set through `classter.identifiers.attributes` of the Vite plugin.\r\n * @param identifiers Names to add (each stored in lowercase and kebab-case).\r\n */\r\n static addAttributesIdentifiers(identifiers: Classter.IDENTIFIER[]): void { for (let i = 0, max = identifiers.length; i < max; i++) Classter.#add(Classter.#ATTRIBUTES_IDENTIFIERS, identifiers[i]) }\r\n\r\n /**\r\n * Registers custom aliases, each mapping a shortcut to a CSS property, on the shared alias table.\r\n * Usually set through `classter.alias` of the Vite plugin.\r\n * Logs a warning and skips the entry when the key is not lowercase letters / hyphens (optionally prefixed with `@`),\r\n * when the key is already used, or when the property is not a valid name (letters, digits, `_`, `-`).\r\n * @param alias Map of shortcut keys to CSS property names.\r\n * @example\r\n * ```ts\r\n * import Vue from 'upwwwards/classter/Vue'\r\n *\r\n * Vue.addAlias({ 'my-pa': 'padding', 'ac-co': 'accent-color' }) // 'ac-co' is already defined: warns and is skipped\r\n *\r\n * // <div class=\"my-pa:1rem\"> now generates .my-pa\\:1rem{padding:1rem}\r\n * ```\r\n */\r\n static addAlias(alias: Record<string, string>): void\r\n {\r\n for (const KEY in alias) switch (true)\r\n {\r\n case !Classter.#RGX_KEY.test(KEY):\r\n Logs.warn('CLASSTER', `KEY \"${KEY}\" IS INVALID.`)\r\n continue\r\n case KEY in PROPS:\r\n Logs.warn('CLASSTER', `KEY \"${KEY}\" IS ALREADY IN USE.`)\r\n continue\r\n default:\r\n const PROP = alias[KEY]\r\n\r\n Classter.#RGX_PROP.test(PROP)\r\n ? PROPS[KEY] = PROP\r\n : Logs.warn('CLASSTER', `THE \"${PROP}\" PROPERTY MUST BE A VALID CSS PROPERTY.`)\r\n }\r\n }\r\n\r\n // ##IS\r\n // static #isSpace(char: string): char is ' ' | '\\t' | '\\n' | '\\r' | '\\f'\r\n // {\r\n // switch (char)\r\n // {\r\n // case ' ' :\r\n // case '\\t':\r\n // case '\\n':\r\n // case '\\r':\r\n // case '\\f': return true\r\n // default : return false\r\n // }\r\n // }\r\n\r\n /**\r\n * Validates a CSS value string: rejects empty values, comments, unbalanced brackets / parens,\r\n * and bare `{` `}` `;` outside quotes.\r\n * @param value Candidate declaration value (already space-normalized from `[…]` tokens).\r\n * @returns `true` when the value is considered safe to emit.\r\n */\r\n static #isValidValue(value: string): boolean\r\n {\r\n if (!value || Classter.#RGX_COMMENT.test(value)) return false\r\n\r\n const STACK = Array(8)\r\n\r\n let\r\n p = 0,\r\n quote = false\r\n\r\n for (let i = 0, max = value.length; i < max; i++)\r\n {\r\n if (quote)\r\n {\r\n const CHAR = value[i]\r\n\r\n if ((CHAR === '\"' || CHAR === '\\'')) quote = false\r\n }\r\n else switch (value[i])\r\n {\r\n case '{':\r\n case '}':\r\n case ';': return false\r\n case '[':\r\n STACK[p++] = 0\r\n break\r\n case ']':\r\n if (STACK[--p] !== 0) return false\r\n break\r\n case '(':\r\n STACK[p++] = 1\r\n break\r\n case ')':\r\n if (STACK[--p] !== 1) return false\r\n break\r\n case '\"' :\r\n case '\\'':\r\n quote = true\r\n break\r\n default:\r\n }\r\n }\r\n \r\n return !p && !quote\r\n }\r\n\r\n // ##RUNNERS\r\n /**\r\n * Splits a whitespace-separated class string and registers each token; falsy values are ignored.\r\n * @param _class Class attribute content (coerced via `toString`).\r\n * @param id Source file id for warnings.\r\n * @internal\r\n */\r\n static [run](_class: string | number | bigint | boolean | RegExp | null | undefined, id: string): void\r\n {\r\n if (!_class) return\r\n\r\n const CLASSES = _class.toString().trim().split(Classter.#RGX_SPLIT)\r\n\r\n for (let i = 0, max = CLASSES.length; i < max; i++) Classter[push](CLASSES[i], id)\r\n }\r\n\r\n /**\r\n * Walks ESTree object properties.\r\n * - `checkKey === true` (e.g. Vue/Svelte `:class` / `class={…}` object maps): register keys as class tokens.\r\n Identifier keys are pushed as-is; string `Literal` keys (e.g. `'pa:1rem'`) and other key expressions go through\r\n `run` / `check` so quoted Classter tokens inside arrays/objects are found.\r\n * - `checkKey === false` (e.g. `v-bind` / spreads / attribute bags): follow values whose key is in\r\n {@link Classter.CLASS_IDENTIFIERS}; if the key is in {@link Classter.ATTRIBUTES_IDENTIFIERS} and the value is an\r\n `ObjectExpression`, recurse (nested `attrs` / `propAttrs` bags).\r\n * Also recurses into object spreads (`…{ … }`).\r\n * @param props Object properties (and spreads).\r\n * @param checkKey When `true`, treat property keys as class tokens; otherwise resolve class / attribute-identifier values.\r\n * @param id Source file id for warnings.\r\n * @internal\r\n */\r\n static [runProperties](props: (Property | SpreadElement)[], checkKey: boolean, id: string): void\r\n {\r\n for (let i = 0, max = props.length; i < max; i++)\r\n {\r\n const PROP = props[i]\r\n\r\n if (PROP.type === 'Property')\r\n {\r\n if (checkKey)\r\n {\r\n if (PROP.key.type === 'Identifier') Classter[push](PROP.key.name, id)\r\n else if (PROP.key.type === 'Literal') Classter[run](PROP.key.value, id)\r\n else Classter[check](PROP.key, false, id)\r\n }\r\n else\r\n {\r\n const KEY = PROP.key.type === 'Identifier'\r\n ? PROP.key.name.toLowerCase()\r\n : PROP.key.type === 'Literal' && typeof PROP.key.value === 'string'\r\n ? PROP.key.value.toLowerCase()\r\n : null\r\n\r\n if (!KEY) continue\r\n \r\n if (Classter.CLASS_IDENTIFIERS.includes(KEY)) Classter[check](PROP.value, false, id)\r\n else if (Classter.ATTRIBUTES_IDENTIFIERS.includes(KEY) && PROP.value.type === 'ObjectExpression') Classter[runProperties](PROP.value.properties, false, id)\r\n }\r\n }\r\n else if (PROP.argument.type === 'ObjectExpression') Classter[runProperties](PROP.argument.properties, checkKey, id)\r\n }\r\n }\r\n\r\n /**\r\n * Runs `check` on each array element (unwraps `SpreadElement`).\r\n * @param els Array expression elements.\r\n * @param toString When `true`, object keys are not treated as classes (string-like evaluation).\r\n * @param id Source file id for warnings.\r\n */\r\n static #runElements(els: (Expression | SpreadElement | null)[], toString: boolean, id: string): void\r\n {\r\n for (let i = 0, max = els.length; i < max; i++)\r\n {\r\n const EL = els[i]\r\n\r\n if (EL) Classter[check](EL.type === 'SpreadElement' ? EL.argument : EL, toString, id)\r\n }\r\n }\r\n\r\n /**\r\n * Runs `check` on each expression in a list.\r\n * @param exprs Expressions to walk.\r\n * @param toString When `true`, object keys are not treated as classes.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runExpressions(exprs: Expression[], toString: boolean, id: string): void { for (let i = 0, max = exprs.length; i < max; i++) Classter[check](exprs[i], toString, id) }\r\n\r\n // ##ANALYZERS\r\n /**\r\n * Analyzes a component source file and registers the class tokens it contains.\r\n * Base implementation does nothing; overridden by `Vue` and `Svelte`. Called by the Vite plugin on transform.\r\n * @param code Source file contents.\r\n * @param id Source file id, used in warnings.\r\n */\r\n static analyze(code: string, id: string): void {}\r\n\r\n /**\r\n * Analyzes raw HTML with a lightweight scan: only double-quoted `class=\"...\"` attributes are read\r\n * (custom class identifiers are ignored).\r\n * @param code Raw HTML / markup string.\r\n * @param id Source file id, used in warnings.\r\n */\r\n static analyzeHTML(code: string, id: string): void\r\n {\r\n let r\r\n\r\n while (r = Classter.#RGX_CLASS_ATTRIBUTE.exec(code)) Classter[run](r[1], id)\r\n }\r\n\r\n // ##UTILS\r\n /**\r\n * Registers one token: parses `alias:value[:pseudo]`, resolves the alias, validates the value and pseudo-element,\r\n * and stores the declaration (sets `updated` on first insert). Tokens not shaped like `alias:value` are ignored silently.\r\n * @param _class Single class token (e.g. `pa:1rem` or `co:[#fff]:before`).\r\n * @param id Source file id for unknown-alias warnings.\r\n * @internal\r\n */\r\n static [push](_class: string, id: string): void\r\n {\r\n const MATCH = _class.match(Classter.#RGX_ANALYZE)\r\n\r\n if (!MATCH) return\r\n\r\n const PROP = PROPS[MATCH[1]]\r\n\r\n if (PROP)\r\n {\r\n const VALUE = MATCH[2] || MATCH[3]?.replace(Classter.#RGX_EXPRESSION_PARSING, ' ').trim()\r\n\r\n if (!Classter.#isValidValue(VALUE)) return Logs.warn('CLASSTER', `THE VALUE IN CLASS \"${_class}\" IS INCORRECT.`)\r\n\r\n const PC = MATCH[4]\r\n\r\n if (PC && !(PC in PROPS)) return Logs.warn('CLASSTER', `PSEUDO-CLASS \"${PC}\" IS NOT SUPPORTED.`)\r\n if (Classter.#MAP.has(_class)) return\r\n\r\n Classter.#MAP.set(_class, [`${PROP}:${VALUE.replace(Classter.#RGX_QUOTE_PARSING, '\"')}`, PC ? PROPS[PC] : ''])\r\n\r\n Classter.updated ||= true\r\n }\r\n else if (Classter.warn) Logs.warn('CLASSTER', `THE ALIAS \"${MATCH[1]}\" IN CLASS \"${_class}\" OF FILE \"${id}\" DOES NOT EXIST.`)\r\n }\r\n\r\n /**\r\n * Walks an ESTree expression and extracts class tokens where statically knowable.\r\n * Supports arrays, `+` of literals, logical / conditional, literals, templates, and objects.\r\n * Identifiers and member expressions are intentionally skipped (runtime values).\r\n * @param expression ESTree node to inspect.\r\n * @param toString When `true`, mimic string coercion (objects not expanded as class maps; arrays with length ≠ 1 skipped).\r\n * @param id Source file id for warnings.\r\n * @internal\r\n */\r\n static [check](expression: Expression | PrivateIdentifier | Pattern, toString: boolean, id: string): void\r\n {\r\n switch (expression.type)\r\n {\r\n case /* ?[x] */ 'ArrayExpression':\r\n if (!toString || expression.elements.length === 1) Classter.#runElements(expression.elements, toString, id)\r\n break\r\n case /* ?x + y */ 'BinaryExpression':\r\n if (expression.operator === '+')\r\n {\r\n if (expression.left.type === 'Literal' && expression.right.type === 'Literal') Classter[run]('' + expression.left.value + expression.right.value, id)\r\n else if (Classter.warn) Logs.warn('CLASSTER', 'UNABLE TO DEDUCE THE EXPRESSION:', expression, 'IN FILE:', id)\r\n }\r\n\r\n break\r\n case /* ?x || y */ 'LogicalExpression':\r\n Classter[check](expression.left, toString, id)\r\n Classter[check](expression.right, toString, id)\r\n break\r\n case /* ?boolean ? x : y */ 'ConditionalExpression':\r\n Classter[check](expression.consequent, toString, id)\r\n Classter[check](expression.alternate, toString, id)\r\n break\r\n case /* ?x */ 'Literal':\r\n Classter[run](expression.value, id)\r\n break\r\n case /* ?`x ${y}` */ 'TemplateLiteral':\r\n for (let i = 0, max = expression.quasis.length; i < max; i++) Classter[run](expression.quasis[i].value.cooked, id)\r\n \r\n Classter.#runExpressions(expression.expressions, toString, id)\r\n \r\n break\r\n case /* ?{var} */ 'Identifier' : // Logs.log((Svelte.#__CURRENT_AST?.instance?.content.body?.[0] as any)?.declarations)\r\n // TODO: Handle the case of variables when iterating through the body (consider all possible cases)\r\n case /* ?Object[key] */ 'MemberExpression': break\r\n case /* ?{ x: y } */ 'ObjectExpression':\r\n if (!toString) Classter[runProperties](expression.properties, true, id)\r\n break\r\n default: if (Classter.warn) Logs.warn('CLASSTER', `THE EXPRESSION \"${expression.type}\" IS NOT CONTROLLED.`)\r\n }\r\n }\r\n\r\n // static #split(_class: string): string[]\r\n // {\r\n // const CLASSES: string[] = []\r\n\r\n // let\r\n // a = -1,\r\n // b = 0\r\n\r\n // for (let i = 0, max = _class.length; i < max; i++)\r\n // {\r\n // const CHAR = _class[i]\r\n\r\n // if (Classter.#isSpace(CHAR))\r\n // {\r\n // if (a === -1 || b > 0) continue\r\n\r\n // CLASSES.push(_class.substring(a, i))\r\n\r\n // a = -1\r\n // }\r\n // else\r\n // {\r\n // if (a === -1) a = i\r\n\r\n // if (CHAR === '[') b++\r\n // else if (CHAR === ']' && b) b-- \r\n // }\r\n // }\r\n\r\n // if (~a) CLASSES.push(_class.substring(a))\r\n\r\n // return CLASSES\r\n // }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Classter\r\n\r\n/**\r\n * Symbol keys of the internal scanning methods, used by the `Vue` and `Svelte` analyzers.\r\n * @internal\r\n*/\r\nexport { run, runProperties, push, check }\r\n\r\nexport type { Classter }"],"mappings":"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","names":[]}
@@ -1,4 +1,4 @@
1
- import { C as Classter } from '../Classter-BvYgmPAa.js';
1
+ import { C as Classter } from '../Classter-DZavFSTW.js';
2
2
  import 'estree';
3
3
 
4
4
  /**
@@ -6,8 +6,11 @@ import 'estree';
6
6
  * to the Vite plugin with the SvelteKit adapter.
7
7
  * It parses the component markup and extracts class tokens from class attributes (custom class identifiers included),
8
8
  * `class:` directives, object-literal spreads and attribute-identifier object literals.
9
- * - `class="x {y}"`: text parts are read as class lists; `{y}` is evaluated like string coercion (object keys ignored).
10
- * - `class={x}`: evaluated with Svelte's `class` rules (object keys and array items are read as classes).
9
+ * - `class="x {y}"`: text parts are read as class lists; `{y}` is evaluated with string-like coercion (`toString`),
10
+ so object keys inside the mustache are ignored.
11
+ * - `class={x}`: evaluated with Svelte's `class` rules (object keys — including string literals such as `'pa:1rem'` —
12
+ and array / template items are read as classes via {@link Classter} AST walk).
13
+ * - Spreads / attribute identifiers use `runProperties(…, false)` (class values + nested attribute bags).
11
14
  * Values only known at runtime (variables, member access) are ignored.
12
15
  */
13
16
  declare abstract class Svelte extends Classter {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/classter/Svelte.ts"],"sourcesContent":["/* [Svelte] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SVELTE\r\nimport { parse } from 'svelte/compiler'\r\n\r\n // ##CLASSTER\r\nimport Classter, { run, runProperties, push, check } from './@/Classter.js'\r\n\r\n // ##TYPES\r\nimport type { AST } from 'svelte/compiler'\r\n\r\n// #TYPES\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Classter analyzer for Svelte 5 components (`upwwwards/classter/Svelte`), to pass as `classter.Classter`\r\n * to the Vite plugin with the SvelteKit adapter.\r\n * It parses the component markup and extracts class tokens from class attributes (custom class identifiers included),\r\n * `class:` directives, object-literal spreads and attribute-identifier object literals.\r\n * - `class=\"x {y}\"`: text parts are read as class lists; `{y}` is evaluated like string coercion (object keys ignored).\r\n * - `class={x}`: evaluated with Svelte's `class` rules (object keys and array items are read as classes).\r\n * Values only known at runtime (variables, member access) are ignored.\r\n*/\r\nabstract class Svelte extends Classter\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n\r\n // ##PRIVATES\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n\r\n // ##GET\r\n\r\n // ##RUNNERS\r\n /**\r\n * Walks fragment nodes (elements, components, control blocks) and recurses into nested fragments.\r\n * @param nodes Fragment child nodes from the modern Svelte AST.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runNodes(nodes: AST.Fragment['nodes'], id: string): void\r\n {\r\n for (let i = 0, max = nodes.length; i < max; i++)\r\n {\r\n const NODE = nodes[i]\r\n \r\n switch (NODE.type)\r\n {\r\n case 'RegularElement' :\r\n case 'Component' :\r\n case 'SvelteComponent':\r\n case 'SlotElement' :\r\n case 'SvelteElement' : Svelte.#runAttributes(NODE.attributes, id)\r\n case 'SvelteFragment' :\r\n case 'SvelteBoundary' :\r\n case 'KeyBlock' :\r\n Svelte.#runNodes(NODE.fragment.nodes, id)\r\n break\r\n case 'IfBlock':\r\n Svelte.#runNodes(NODE.consequent.nodes, id)\r\n \r\n if (NODE.alternate) Svelte.#runNodes(NODE.alternate.nodes, id)\r\n \r\n break\r\n case 'SnippetBlock':\r\n case 'EachBlock' :\r\n Svelte.#runNodes(NODE.body.nodes, id)\r\n break\r\n case 'AwaitBlock':\r\n if (NODE.pending) Svelte.#runNodes(NODE.pending.nodes, id)\r\n if (NODE.then) Svelte.#runNodes(NODE.then.nodes, id)\r\n if (NODE.catch) Svelte.#runNodes(NODE.catch.nodes, id)\r\n default:\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Extracts classes from element / component attributes:\r\n * `class:x` directives, object-literal spreads, class identifiers, and attribute-identifier object literals.\r\n * @param attrs Attribute / directive / spread list.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runAttributes(attrs: (AST.AttachTag | AST.Attribute | AST.SpreadAttribute | AST.Directive)[], id: string): void\r\n {\r\n for (let i = 0, max = attrs.length; i < max; i++)\r\n {\r\n const ATTR = attrs[i]\r\n\r\n switch (ATTR.type)\r\n {\r\n case 'ClassDirective': // ?class:x={...}\r\n Svelte[push](ATTR.name, id)\r\n break\r\n case 'SpreadAttribute':\r\n if (ATTR.expression.type === 'ObjectExpression') Svelte[runProperties](ATTR.expression.properties, false, id)\r\n break\r\n case 'Attribute':\r\n const NAME = ATTR.name.toLowerCase()\r\n \r\n if (Svelte.CLASS_IDENTIFIERS.includes(NAME))\r\n {\r\n if (Array.isArray(ATTR.value)) Svelte.#runAttributeValues(ATTR.value, id) // ?class=\"x {y}\"\r\n else if (typeof ATTR.value === 'object') Svelte[check](ATTR.value.expression, false, id) // ?class={x}\r\n }\r\n else if (Svelte.ATTRIBUTES_IDENTIFIERS.includes(NAME) && typeof ATTR.value === 'object' && !Array.isArray(ATTR.value) && ATTR.value.expression.type === 'ObjectExpression') Svelte[runProperties](ATTR.value.expression.properties, false, id)\r\n default:\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Walks mixed text / expression values of a quoted attribute (`class=\"x {y}\"`).\r\n * Text → `run`; expressions → `check(…, true)` (string-like).\r\n * @param vals Attribute value segments.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runAttributeValues(vals: (AST.Text | AST.ExpressionTag)[], id: string): void\r\n {\r\n for (let i = 0, max = vals.length; i < max; i++)\r\n {\r\n const VAL = vals[i]\r\n\r\n VAL.type === 'Text' ? Svelte[run](VAL.data, id) : Svelte[check](VAL.expression, true, id)\r\n }\r\n }\r\n\r\n // ##ANALYZERS\r\n /**\r\n * Parses a Svelte component (modern AST) and registers the class tokens found in its markup.\r\n * @param code Full `.svelte` file source.\r\n * @param id Source file id, used in warnings.\r\n */\r\n static override analyze(code: string, id: string): void { Svelte.#runNodes(parse(code, { modern: true }).fragment.nodes, id) }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Svelte"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/classter/Svelte.ts"],"sourcesContent":["/* [Svelte] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SVELTE\r\nimport { parse } from 'svelte/compiler'\r\n\r\n // ##CLASSTER\r\nimport Classter, { run, runProperties, push, check } from './@/Classter.js'\r\n\r\n // ##TYPES\r\nimport type { AST } from 'svelte/compiler'\r\n\r\n// #TYPES\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Classter analyzer for Svelte 5 components (`upwwwards/classter/Svelte`), to pass as `classter.Classter`\r\n * to the Vite plugin with the SvelteKit adapter.\r\n * It parses the component markup and extracts class tokens from class attributes (custom class identifiers included),\r\n * `class:` directives, object-literal spreads and attribute-identifier object literals.\r\n * - `class=\"x {y}\"`: text parts are read as class lists; `{y}` is evaluated with string-like coercion (`toString`),\r\n so object keys inside the mustache are ignored.\r\n * - `class={x}`: evaluated with Svelte's `class` rules (object keys — including string literals such as `'pa:1rem'` —\r\n and array / template items are read as classes via {@link Classter} AST walk).\r\n * - Spreads / attribute identifiers use `runProperties(…, false)` (class values + nested attribute bags).\r\n * Values only known at runtime (variables, member access) are ignored.\r\n*/\r\nabstract class Svelte extends Classter\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n\r\n // ##PRIVATES\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n\r\n // ##GET\r\n\r\n // ##RUNNERS\r\n /**\r\n * Walks fragment nodes (elements, components, control blocks) and recurses into nested fragments.\r\n * @param nodes Fragment child nodes from the modern Svelte AST.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runNodes(nodes: AST.Fragment['nodes'], id: string): void\r\n {\r\n for (let i = 0, max = nodes.length; i < max; i++)\r\n {\r\n const NODE = nodes[i]\r\n \r\n switch (NODE.type)\r\n {\r\n case 'RegularElement' :\r\n case 'Component' :\r\n case 'SvelteComponent':\r\n case 'SlotElement' :\r\n case 'SvelteElement' : Svelte.#runAttributes(NODE.attributes, id)\r\n case 'SvelteFragment' :\r\n case 'SvelteBoundary' :\r\n case 'KeyBlock' :\r\n Svelte.#runNodes(NODE.fragment.nodes, id)\r\n break\r\n case 'IfBlock':\r\n Svelte.#runNodes(NODE.consequent.nodes, id)\r\n \r\n if (NODE.alternate) Svelte.#runNodes(NODE.alternate.nodes, id)\r\n \r\n break\r\n case 'SnippetBlock':\r\n case 'EachBlock' :\r\n Svelte.#runNodes(NODE.body.nodes, id)\r\n break\r\n case 'AwaitBlock':\r\n if (NODE.pending) Svelte.#runNodes(NODE.pending.nodes, id)\r\n if (NODE.then) Svelte.#runNodes(NODE.then.nodes, id)\r\n if (NODE.catch) Svelte.#runNodes(NODE.catch.nodes, id)\r\n default:\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Extracts classes from element / component attributes:\r\n * `class:x` directives, object-literal spreads, class identifiers, and attribute-identifier object literals.\r\n * @param attrs Attribute / directive / spread list.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runAttributes(attrs: (AST.AttachTag | AST.Attribute | AST.SpreadAttribute | AST.Directive)[], id: string): void\r\n {\r\n for (let i = 0, max = attrs.length; i < max; i++)\r\n {\r\n const ATTR = attrs[i]\r\n\r\n switch (ATTR.type)\r\n {\r\n case 'ClassDirective': // ?class:x={...}\r\n Svelte[push](ATTR.name, id)\r\n break\r\n case 'SpreadAttribute':\r\n if (ATTR.expression.type === 'ObjectExpression') Svelte[runProperties](ATTR.expression.properties, false, id)\r\n break\r\n case 'Attribute':\r\n const NAME = ATTR.name.toLowerCase()\r\n \r\n if (Svelte.CLASS_IDENTIFIERS.includes(NAME))\r\n {\r\n if (Array.isArray(ATTR.value)) Svelte.#runAttributeValues(ATTR.value, id) // ?class=\"x {y}\"\r\n else if (typeof ATTR.value === 'object') Svelte[check](ATTR.value.expression, false, id) // ?class={x}\r\n }\r\n else if (Svelte.ATTRIBUTES_IDENTIFIERS.includes(NAME) && typeof ATTR.value === 'object' && !Array.isArray(ATTR.value) && ATTR.value.expression.type === 'ObjectExpression') Svelte[runProperties](ATTR.value.expression.properties, false, id)\r\n default:\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Walks mixed text / expression values of a quoted attribute (`class=\"x {y}\"`).\r\n * Text → `run`; expressions → `check(…, true)` (string-like).\r\n * @param vals Attribute value segments.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runAttributeValues(vals: (AST.Text | AST.ExpressionTag)[], id: string): void\r\n {\r\n for (let i = 0, max = vals.length; i < max; i++)\r\n {\r\n const VAL = vals[i]\r\n\r\n VAL.type === 'Text' ? Svelte[run](VAL.data, id) : Svelte[check](VAL.expression, true, id)\r\n }\r\n }\r\n\r\n // ##ANALYZERS\r\n /**\r\n * Parses a Svelte component (modern AST) and registers the class tokens found in its markup.\r\n * @param code Full `.svelte` file source.\r\n * @param id Source file id, used in warnings.\r\n */\r\n static override analyze(code: string, id: string): void { Svelte.#runNodes(parse(code, { modern: true }).fragment.nodes, id) }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Svelte"],"mappings":"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","names":[]}
@@ -1,13 +1,15 @@
1
- import { C as Classter } from '../Classter-BvYgmPAa.js';
1
+ import { C as Classter } from '../Classter-DZavFSTW.js';
2
2
  import 'estree';
3
3
 
4
4
  /**
5
5
  * Classter analyzer for Vue single-file components (`upwwwards/classter/Vue`), to pass as `classter.Classter`
6
6
  * to the Vite plugin with the Nuxt adapter.
7
7
  * It parses the `<template>` block and extracts class tokens from static `class` attributes, `:class` / `v-bind:class`
8
- * bindings, and `v-bind="{ ... }"` object literals (custom class / attribute identifiers included).
9
- * Binding expressions are read statically: string, template, array and object literals with lightweight parsing,
10
- * other expressions with the Meriyah parser. Values only known at runtime (variables, member access) are ignored.
8
+ * bindings, and `v-bind="{ … }"` object literals (custom class / attribute identifiers included).
9
+ * Binding expressions are analyzed statically: plain string literals are split directly; everything else is parsed with
10
+ * Meriyah (wrapped in `(…)` so object literals are not mistaken for blocks) and walked by {@link Classter} (`check` /
11
+ * `runProperties`). Nested template literals, arrays and object class maps are supported. Runtime-only values
12
+ * (identifiers, member access) are ignored.
11
13
  */
12
14
  declare abstract class Vue extends Classter {
13
15
  #private;
@@ -1,14 +1,10 @@
1
1
  import { parse } from "@vue/compiler-sfc";
2
2
  import { baseParse, NodeTypes } from "@vue/compiler-dom";
3
3
  import { parseScript } from "meriyah";
4
- import Classter, { run, push, check } from "./@/Classter.js";
4
+ import Classter, { run, runProperties, check } from "./@/Classter.js";
5
5
  class Vue extends Classter {
6
6
  // #PROPS
7
7
  // ##STATICS
8
- static #RGX_TEMPLATE_LITERAL = /\$\{([^}]*)\}/g;
9
- static #RGX_ARRAY = /(?:(?<!\$){.*?})|(?:(?<!\\)(["'`]).*?(?<!\\)\1)/g;
10
- static #RGX_OBJECT = /(?:^|[,{]\s*)(?:(?<!\\)(["'])(.*?)(?<!\\)\1)|([A-Za-z_$][\w$-]*)\s*:/g;
11
- static #RGX_VBIND_OBJECT = /(?:^|[,{]\s*)(?:(?:(?<!\\)(["'])(?<qkey>.*?)(?<!\\)\1)|(?<ikey>[A-Za-z_$][\w$-]*))\s*:\s*(?<val>(?:(?:{.*})|(?:\[.*])|(?:(?<!\\)(['"`]).*?(?<!\\)\5)|[^,}]+))\s*/g;
12
8
  // ##PRIVATES
13
9
  // ##PUBLICS
14
10
  // #MANAGERS
@@ -19,28 +15,15 @@ class Vue extends Classter {
19
15
  // ##GET
20
16
  // ##IS
21
17
  /**
22
- * Checks whether an expression is a quoted string literal.
18
+ * Checks whether an expression is a single quoted string literal (not e.g. `'a' + 'b'`).
23
19
  * @param s Expression string.
24
- * @returns `true` when `s` is a single- or double-quoted string literal.
20
+ * @returns `true` when `s` is one `'…'` or `"…"` literal with no unescaped quote inside.
25
21
  */
26
22
  static #isLiteral(s) {
27
- return s.startsWith('"') ? s.endsWith('"') : s.startsWith("'") && s.endsWith("'");
28
- }
29
- /**
30
- * Checks whether an expression is a template literal.
31
- * @param s Expression string.
32
- * @returns `true` when `s` is a backtick template literal.
33
- */
34
- static #isTemplateLiteral(s) {
35
- return s.startsWith("`") && s.endsWith("`");
36
- }
37
- /**
38
- * Checks whether an expression looks like an array literal.
39
- * @param s Expression string.
40
- * @returns `true` when `s` looks like an array literal `[…]`.
41
- */
42
- static #isArray(s) {
43
- return s.startsWith("[") && s.endsWith("]");
23
+ const Q = s[0];
24
+ if (Q !== '"' && Q !== "'" || s.length < 2 || s.at(-1) !== Q) return false;
25
+ for (let i = 1, max = s.length - 1; i < max; i++) if (s[i] === Q && s[i - 1] !== "\\") return false;
26
+ return true;
44
27
  }
45
28
  /**
46
29
  * Checks whether an expression looks like an object literal.
@@ -62,8 +45,8 @@ class Vue extends Classter {
62
45
  /**
63
46
  * Extracts classes from element props.
64
47
  * - `class="x y"` (or a custom class identifier): direct extraction.
65
- * - `:class` / `v-bind:class`: static analysis of the expression; `:attrs` with an attribute identifier: object scan.
66
- * - `v-bind="{ class: … }"`: object scan when the value is an object literal.
48
+ * - `:class` / `v-bind:class`: Meriyah + AST walk of the expression.
49
+ * - Attribute identifiers / `v-bind="{ … }"`: `runProperties(…, false)` (class values + nested attribute bags).
67
50
  * Dynamic argument names (`:[name]`) are skipped.
68
51
  * @param props Element attributes and directives.
69
52
  * @param id Source file id for warnings.
@@ -119,81 +102,28 @@ class Vue extends Classter {
119
102
  }
120
103
  // ##UTILS
121
104
  /**
122
- * Classifies a binding expression string and dispatches to the matching checker, or to a Meriyah parse.
105
+ * Classifies a `:class` / class-identifier binding: plain string literals go to `run`; otherwise Meriyah parses
106
+ * the expression (as `(…)`) and `check` walks the AST (templates, arrays, objects, conditionals, …).
123
107
  * Expressions shorter than two characters are ignored.
124
108
  * @param expression Expression content from a directive (trimmed here).
125
109
  * @param id Source file id for warnings.
126
110
  */
127
111
  static #checkExpression(expression, id) {
128
112
  const EXPRESSION = expression.trim();
129
- switch (true) {
130
- case EXPRESSION.length < 2:
131
- return;
132
- case Vue.#isLiteral(EXPRESSION):
133
- return Vue[run](EXPRESSION.slice(1, -1), id);
134
- case Vue.#isTemplateLiteral(EXPRESSION):
135
- return Vue.#checkTemplateLiteralExpression(EXPRESSION, id);
136
- case Vue.#isArray(EXPRESSION):
137
- return Vue.#checkArrayExpression(EXPRESSION, id);
138
- case Vue.#isObject(EXPRESSION):
139
- return Vue.#checkObjectExpression(EXPRESSION, id);
140
- default:
141
- Vue.#runProgram(parseScript(EXPRESSION, { next: true }), id);
142
- }
113
+ if (EXPRESSION.length > 1) Vue.#isLiteral(EXPRESSION) ? Vue[run](EXPRESSION.slice(1, -1), id) : Vue.#runProgram(parseScript(`(${EXPRESSION})`, { next: true }), id);
143
114
  }
144
115
  /**
145
- * Splits a template literal into static runs and `${…}` interpolations, registering both.
146
- * @param templateLiteral Backtick-wrapped expression.
147
- * @param id Source file id for warnings.
148
- */
149
- static #checkTemplateLiteralExpression(templateLiteral, id) {
150
- const S = templateLiteral.slice(1, -1);
151
- let x = null, i = 0;
152
- while (x = Vue.#RGX_TEMPLATE_LITERAL.exec(S)) {
153
- const { 0: X, 1: Y, index: I } = x;
154
- Vue[run](S.substring(i, I), id);
155
- Vue.#checkExpression(Y, id);
156
- i = I + X.length;
157
- }
158
- Vue[run](S.substring(i), id);
159
- }
160
- /**
161
- * Heuristically extracts string / object / template entries from an array literal expression.
162
- * @param array Bracket-wrapped expression.
163
- * @param id Source file id for warnings.
164
- */
165
- static #checkArrayExpression(array, id) {
166
- let r;
167
- while (r = Vue.#RGX_ARRAY.exec(array)) {
168
- const MATCH = r[0];
169
- Vue.#isObject(MATCH) ? Vue.#checkObjectExpression(MATCH, id) : Vue.#isTemplateLiteral(MATCH) ? Vue.#checkTemplateLiteralExpression(MATCH, id) : Vue[run](MATCH.slice(1, -1), id);
170
- }
171
- }
172
- /**
173
- * Heuristically pushes object keys as class tokens (Vue object-syntax `:class`).
174
- * @param object Brace-wrapped expression.
175
- * @param id Source file id for warnings.
176
- */
177
- static #checkObjectExpression(object, id) {
178
- let r;
179
- while (r = Vue.#RGX_OBJECT.exec(object)) Vue[push](r[2] ?? r[3], id);
180
- }
181
- /**
182
- * Heuristically walks a `v-bind="{ … }"` object: values of class identifiers are analyzed as class expressions,
183
- * values of attribute identifiers are walked as nested objects. Non-object expressions are ignored.
116
+ * Walks a `v-bind="{ … }"` / attribute-identifier object via Meriyah + `runProperties(…, false)`:
117
+ * values of {@link Classter.CLASS_IDENTIFIERS} are analyzed as class expressions; values of
118
+ * {@link Classter.ATTRIBUTES_IDENTIFIERS} that are object literals are recursed into. Non-object expressions are ignored.
184
119
  * @param object Expression expected to be an object literal.
185
120
  * @param id Source file id for warnings.
186
121
  */
187
122
  static #checkVBindObject(object, id) {
188
123
  const OBJECT = object.trim();
189
124
  if (!Vue.#isObject(OBJECT)) return;
190
- let r;
191
- while (r = Vue.#RGX_VBIND_OBJECT.exec(OBJECT)) {
192
- if (!r.groups) continue;
193
- const KEY = (r.groups.qkey ?? r.groups.ikey).toLowerCase(), VAL = r.groups.val.trim();
194
- if (Vue.CLASS_IDENTIFIERS.includes(KEY)) Vue.#checkExpression(VAL, id);
195
- else if (Vue.ATTRIBUTES_IDENTIFIERS.includes(KEY)) Vue.#checkVBindObject(VAL, id);
196
- }
125
+ const NODE = parseScript(`(${OBJECT})`, { next: true }).body[0];
126
+ if (NODE?.type === "ExpressionStatement" && NODE.expression.type === "ObjectExpression") Vue[runProperties](NODE.expression.properties, false, id);
197
127
  }
198
128
  /**
199
129
  * Dispatches a template AST node (root, element, `v-if`, `v-for`, …).
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/classter/Vue.ts"],"sourcesContent":["/* [Vue] */\r\n\r\n// #IMPORTS\r\n\r\n // ##VUE\r\nimport { parse } from '@vue/compiler-sfc'\r\nimport { baseParse, NodeTypes } from '@vue/compiler-dom'\r\n\r\n // ##MERIYAH\r\nimport { parseScript } from 'meriyah'\r\n\r\n // ##CLASSTER\r\nimport Classter, { run, push, check } from './@/Classter.js'\r\n\r\n // ##TYPES\r\nimport type { AttributeNode, DirectiveNode, RootNode, TemplateChildNode, IfBranchNode } from '@vue/compiler-dom'\r\n\r\nimport type { Program } from 'estree'\r\n\r\n// #TYPES\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Classter analyzer for Vue single-file components (`upwwwards/classter/Vue`), to pass as `classter.Classter`\r\n * to the Vite plugin with the Nuxt adapter.\r\n * It parses the `<template>` block and extracts class tokens from static `class` attributes, `:class` / `v-bind:class`\r\n * bindings, and `v-bind=\"{ ... }\"` object literals (custom class / attribute identifiers included).\r\n * Binding expressions are read statically: string, template, array and object literals with lightweight parsing,\r\n * other expressions with the Meriyah parser. Values only known at runtime (variables, member access) are ignored.\r\n*/\r\nabstract class Vue extends Classter\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n static #RGX_TEMPLATE_LITERAL = /\\$\\{([^}]*)\\}/g\r\n static #RGX_ARRAY = /(?:(?<!\\$){.*?})|(?:(?<!\\\\)([\"'`]).*?(?<!\\\\)\\1)/g\r\n static #RGX_OBJECT = /(?:^|[,{]\\s*)(?:(?<!\\\\)([\"'])(.*?)(?<!\\\\)\\1)|([A-Za-z_$][\\w$-]*)\\s*:/g\r\n static #RGX_VBIND_OBJECT = /(?:^|[,{]\\s*)(?:(?:(?<!\\\\)([\"'])(?<qkey>.*?)(?<!\\\\)\\1)|(?<ikey>[A-Za-z_$][\\w$-]*))\\s*:\\s*(?<val>(?:(?:{.*})|(?:\\[.*])|(?:(?<!\\\\)(['\"`]).*?(?<!\\\\)\\5)|[^,}]+))\\s*/g\r\n\r\n // ##PRIVATES\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n\r\n // ##GET\r\n\r\n // ##IS\r\n /**\r\n * Checks whether an expression is a quoted string literal.\r\n * @param s Expression string.\r\n * @returns `true` when `s` is a single- or double-quoted string literal.\r\n */\r\n static #isLiteral(s: string): s is `\"${string}\"` | `'${string}'` { return s.startsWith('\"') ? s.endsWith('\"') : s.startsWith(\"'\") && s.endsWith(\"'\") }\r\n\r\n /**\r\n * Checks whether an expression is a template literal.\r\n * @param s Expression string.\r\n * @returns `true` when `s` is a backtick template literal.\r\n */\r\n static #isTemplateLiteral(s: string): s is `\\`${string}\\`` { return s.startsWith('`') && s.endsWith('`') }\r\n\r\n /**\r\n * Checks whether an expression looks like an array literal.\r\n * @param s Expression string.\r\n * @returns `true` when `s` looks like an array literal `[…]`.\r\n */\r\n static #isArray(s: string): s is `[${string}]` { return s.startsWith('[') && s.endsWith(']') }\r\n\r\n /**\r\n * Checks whether an expression looks like an object literal.\r\n * @param s Expression string.\r\n * @returns `true` when `s` looks like an object literal `{…}`.\r\n */\r\n static #isObject(s: string): s is `{${string}}` { return s.startsWith('{') && s.endsWith('}') }\r\n\r\n // ##RUNNERS\r\n /**\r\n * Walks template child nodes.\r\n * @param children Template AST children.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runChildren(children: TemplateChildNode[], id: string): void { for (let i = 0, max = children.length; i < max; i++) Vue.#checkNode(children[i], id) }\r\n\r\n /**\r\n * Extracts classes from element props.\r\n * - `class=\"x y\"` (or a custom class identifier): direct extraction.\r\n * - `:class` / `v-bind:class`: static analysis of the expression; `:attrs` with an attribute identifier: object scan.\r\n * - `v-bind=\"{ class: … }\"`: object scan when the value is an object literal.\r\n * Dynamic argument names (`:[name]`) are skipped.\r\n * @param props Element attributes and directives.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runProps(props: (AttributeNode | DirectiveNode)[], id: string): void\r\n {\r\n for (let i = 0, max = props.length; i < max; i++)\r\n {\r\n const PROP = props[i]\r\n\r\n if (PROP.type === NodeTypes.ATTRIBUTE)\r\n {\r\n if (Vue.CLASS_IDENTIFIERS.includes(PROP.name.toLowerCase())) Vue[run](PROP.value?.content, id)\r\n }\r\n else if (PROP.name === 'bind' && PROP.exp?.type === NodeTypes.SIMPLE_EXPRESSION) // v-bind:class / :class\r\n {\r\n if (PROP.arg?.type === NodeTypes.SIMPLE_EXPRESSION)\r\n {\r\n if (!PROP.arg.isStatic) continue // cas exotique: :[dynamic]=\"...\"\r\n\r\n if (PROP.arg.content)\r\n {\r\n const IDENTIFIER = PROP.arg.content.toLowerCase()\r\n \r\n if (Vue.CLASS_IDENTIFIERS.includes(IDENTIFIER)) Vue.#checkExpression(PROP.exp.content, id)\r\n if (Vue.ATTRIBUTES_IDENTIFIERS.includes(IDENTIFIER)) Vue.#checkVBindObject(PROP.exp.content, id)\r\n\r\n continue\r\n }\r\n }\r\n\r\n Vue.#checkVBindObject(PROP.exp.content, id) // v-bind=\"obj\"\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Walks all branches of a `v-if` / `v-else-if` / `v-else` chain.\r\n * @param branches IF branches from the template AST.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runIf(branches: IfBranchNode[], id: string): void { for (let i = 0, max = branches.length; i < max; i++) Vue.#runChildren(branches[i].children, id) }\r\n\r\n /**\r\n * Runs `check` on top-level expression statements of a Meriyah program.\r\n * @param body Program body (destructured as `{ body }`).\r\n * @param id Source file id for warnings.\r\n */\r\n static #runProgram({body}: Program, id: string): void\r\n {\r\n for (let i = 0, max = body.length; i < max; i++)\r\n {\r\n const NODE = body[i]\r\n\r\n if (NODE.type === 'ExpressionStatement') Vue[check](NODE.expression, false, id)\r\n }\r\n }\r\n\r\n // ##ANALYZERS\r\n /**\r\n * Parses a Vue single-file component and registers the class tokens of its `<template>` block.\r\n * Components without a template are ignored.\r\n * @param code Full `.vue` file source.\r\n * @param id Source file id, used in warnings.\r\n */\r\n static override analyze(code: string, id: string): void\r\n {\r\n const TEMPLATE = parse(code).descriptor.template?.content\r\n\r\n if (TEMPLATE) Vue.#checkNode(baseParse(TEMPLATE), id) // baseParse attend du HTML de template (sans <template> wrapper)\r\n }\r\n\r\n // ##UTILS\r\n /**\r\n * Classifies a binding expression string and dispatches to the matching checker, or to a Meriyah parse.\r\n * Expressions shorter than two characters are ignored.\r\n * @param expression Expression content from a directive (trimmed here).\r\n * @param id Source file id for warnings.\r\n */\r\n static #checkExpression(expression: string, id: string): void\r\n {\r\n const EXPRESSION = expression.trim()\r\n\r\n switch (true)\r\n {\r\n case EXPRESSION.length < 2 : return\r\n case Vue.#isLiteral(EXPRESSION) : return Vue[run](EXPRESSION.slice(1, -1), id)\r\n case Vue.#isTemplateLiteral(EXPRESSION): return Vue.#checkTemplateLiteralExpression(EXPRESSION, id)\r\n case Vue.#isArray(EXPRESSION) : return Vue.#checkArrayExpression(EXPRESSION, id)\r\n case Vue.#isObject(EXPRESSION) : return Vue.#checkObjectExpression(EXPRESSION, id)\r\n default : Vue.#runProgram(parseScript(EXPRESSION, { next: true }) as Program, id)\r\n }\r\n }\r\n\r\n /**\r\n * Splits a template literal into static runs and `${…}` interpolations, registering both.\r\n * @param templateLiteral Backtick-wrapped expression.\r\n * @param id Source file id for warnings.\r\n */\r\n static #checkTemplateLiteralExpression(templateLiteral: `\\`${string}\\``, id: string): void\r\n {\r\n const S = templateLiteral.slice(1, -1)\r\n\r\n let\r\n x: RegExpExecArray | null = null,\r\n i = 0\r\n\r\n while (x = Vue.#RGX_TEMPLATE_LITERAL.exec(S))\r\n {\r\n const {0: X, 1: Y, index: I} = x\r\n\r\n Vue[run](S.substring(i, I), id)\r\n Vue.#checkExpression(Y, id)\r\n\r\n i = I + X.length\r\n }\r\n\r\n Vue[run](S.substring(i), id)\r\n }\r\n\r\n /**\r\n * Heuristically extracts string / object / template entries from an array literal expression.\r\n * @param array Bracket-wrapped expression.\r\n * @param id Source file id for warnings.\r\n */\r\n static #checkArrayExpression(array: `[${string}]`, id: string): void\r\n {\r\n let r: RegExpExecArray | null\r\n\r\n while (r = Vue.#RGX_ARRAY.exec(array))\r\n {\r\n const MATCH = r[0]\r\n\r\n Vue.#isObject(MATCH)\r\n ? Vue.#checkObjectExpression(MATCH, id)\r\n : Vue.#isTemplateLiteral(MATCH)\r\n ? Vue.#checkTemplateLiteralExpression(MATCH, id)\r\n : Vue[run](MATCH.slice(1, -1), id)\r\n }\r\n }\r\n\r\n /**\r\n * Heuristically pushes object keys as class tokens (Vue object-syntax `:class`).\r\n * @param object Brace-wrapped expression.\r\n * @param id Source file id for warnings.\r\n */\r\n static #checkObjectExpression(object: `{${string}}`, id: string): void\r\n {\r\n let r: RegExpExecArray | null\r\n\r\n while (r = Vue.#RGX_OBJECT.exec(object)) Vue[push](r[2] ?? r[3], id)\r\n }\r\n\r\n /**\r\n * Heuristically walks a `v-bind=\"{ … }\"` object: values of class identifiers are analyzed as class expressions,\r\n * values of attribute identifiers are walked as nested objects. Non-object expressions are ignored.\r\n * @param object Expression expected to be an object literal.\r\n * @param id Source file id for warnings.\r\n */\r\n static #checkVBindObject(object: string, id: string): void\r\n {\r\n const OBJECT = object.trim()\r\n\r\n if (!Vue.#isObject(OBJECT)) return\r\n\r\n let r: RegExpExecArray | null\r\n\r\n while (r = Vue.#RGX_VBIND_OBJECT.exec(OBJECT))\r\n {\r\n if (!r.groups) continue\r\n \r\n const\r\n KEY = (r.groups.qkey ?? r.groups.ikey).toLowerCase(),\r\n VAL = r.groups.val.trim()\r\n\r\n if (Vue.CLASS_IDENTIFIERS.includes(KEY)) Vue.#checkExpression(VAL, id)\r\n else if (Vue.ATTRIBUTES_IDENTIFIERS.includes(KEY)) Vue.#checkVBindObject(VAL, id)\r\n }\r\n }\r\n\r\n /**\r\n * Dispatches a template AST node (root, element, `v-if`, `v-for`, …).\r\n * @param node Template node to inspect.\r\n * @param id Source file id for warnings.\r\n */\r\n static #checkNode(node: RootNode | TemplateChildNode, id: string): void\r\n {\r\n switch (node.type)\r\n {\r\n case NodeTypes.ROOT:\r\n Vue.#runChildren(node.children, id)\r\n break\r\n case NodeTypes.ELEMENT:\r\n Vue.#runProps(node.props, id)\r\n Vue.#runChildren(node.children, id)\r\n break\r\n case NodeTypes.IF:\r\n Vue.#runIf(node.branches, id)\r\n break\r\n case NodeTypes.FOR:\r\n Vue.#runChildren(node.children, id)\r\n break\r\n default:\r\n }\r\n }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Vue"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/classter/Vue.ts"],"sourcesContent":["/* [Vue] */\r\n\r\n// #IMPORTS\r\n\r\n // ##VUE\r\nimport { parse } from '@vue/compiler-sfc'\r\nimport { baseParse, NodeTypes } from '@vue/compiler-dom'\r\n\r\n // ##MERIYAH\r\nimport { parseScript } from 'meriyah'\r\n\r\n // ##CLASSTER\r\nimport Classter, { run, runProperties, check } from './@/Classter.js'\r\n\r\n // ##TYPES\r\nimport type { AttributeNode, DirectiveNode, RootNode, TemplateChildNode, IfBranchNode } from '@vue/compiler-dom'\r\n\r\nimport type { Program } from 'estree'\r\n\r\n// #TYPES\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Classter analyzer for Vue single-file components (`upwwwards/classter/Vue`), to pass as `classter.Classter`\r\n * to the Vite plugin with the Nuxt adapter.\r\n * It parses the `<template>` block and extracts class tokens from static `class` attributes, `:class` / `v-bind:class`\r\n * bindings, and `v-bind=\"{ … }\"` object literals (custom class / attribute identifiers included).\r\n * Binding expressions are analyzed statically: plain string literals are split directly; everything else is parsed with\r\n * Meriyah (wrapped in `(…)` so object literals are not mistaken for blocks) and walked by {@link Classter} (`check` /\r\n * `runProperties`). Nested template literals, arrays and object class maps are supported. Runtime-only values\r\n * (identifiers, member access) are ignored.\r\n*/\r\nabstract class Vue extends Classter\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n\r\n // ##PRIVATES\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n\r\n // ##GET\r\n\r\n // ##IS\r\n /**\r\n * Checks whether an expression is a single quoted string literal (not e.g. `'a' + 'b'`).\r\n * @param s Expression string.\r\n * @returns `true` when `s` is one `'…'` or `\"…\"` literal with no unescaped quote inside.\r\n */\r\n static #isLiteral(s: string): s is `\"${string}\"` | `'${string}'`\r\n {\r\n const Q = s[0]\r\n\r\n if ((Q !== '\"' && Q !== \"'\") || s.length < 2 || s.at(-1) !== Q) return false\r\n\r\n // *Reject `'a' + 'b'` etc.: an unescaped quote inside means this is not a single literal.\r\n for (let i = 1, max = s.length - 1; i < max; i++) if (s[i] === Q && s[i - 1] !== '\\\\') return false\r\n\r\n return true\r\n }\r\n\r\n /**\r\n * Checks whether an expression looks like an object literal.\r\n * @param s Expression string.\r\n * @returns `true` when `s` looks like an object literal `{…}`.\r\n */\r\n static #isObject(s: string): s is `{${string}}` { return s.startsWith('{') && s.endsWith('}') }\r\n\r\n // ##RUNNERS\r\n /**\r\n * Walks template child nodes.\r\n * @param children Template AST children.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runChildren(children: TemplateChildNode[], id: string): void { for (let i = 0, max = children.length; i < max; i++) Vue.#checkNode(children[i], id) }\r\n\r\n /**\r\n * Extracts classes from element props.\r\n * - `class=\"x y\"` (or a custom class identifier): direct extraction.\r\n * - `:class` / `v-bind:class`: Meriyah + AST walk of the expression.\r\n * - Attribute identifiers / `v-bind=\"{ … }\"`: `runProperties(…, false)` (class values + nested attribute bags).\r\n * Dynamic argument names (`:[name]`) are skipped.\r\n * @param props Element attributes and directives.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runProps(props: (AttributeNode | DirectiveNode)[], id: string): void\r\n {\r\n for (let i = 0, max = props.length; i < max; i++)\r\n {\r\n const PROP = props[i]\r\n\r\n if (PROP.type === NodeTypes.ATTRIBUTE)\r\n {\r\n if (Vue.CLASS_IDENTIFIERS.includes(PROP.name.toLowerCase())) Vue[run](PROP.value?.content, id)\r\n }\r\n else if (PROP.name === 'bind' && PROP.exp?.type === NodeTypes.SIMPLE_EXPRESSION) // v-bind:class / :class\r\n {\r\n if (PROP.arg?.type === NodeTypes.SIMPLE_EXPRESSION)\r\n {\r\n if (!PROP.arg.isStatic) continue // cas exotique: :[dynamic]=\"...\"\r\n\r\n if (PROP.arg.content)\r\n {\r\n const IDENTIFIER = PROP.arg.content.toLowerCase()\r\n \r\n if (Vue.CLASS_IDENTIFIERS.includes(IDENTIFIER)) Vue.#checkExpression(PROP.exp.content, id)\r\n if (Vue.ATTRIBUTES_IDENTIFIERS.includes(IDENTIFIER)) Vue.#checkVBindObject(PROP.exp.content, id)\r\n\r\n continue\r\n }\r\n }\r\n\r\n Vue.#checkVBindObject(PROP.exp.content, id) // v-bind=\"obj\"\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Walks all branches of a `v-if` / `v-else-if` / `v-else` chain.\r\n * @param branches IF branches from the template AST.\r\n * @param id Source file id for warnings.\r\n */\r\n static #runIf(branches: IfBranchNode[], id: string): void { for (let i = 0, max = branches.length; i < max; i++) Vue.#runChildren(branches[i].children, id) }\r\n\r\n /**\r\n * Runs `check` on top-level expression statements of a Meriyah program.\r\n * @param body Program body (destructured as `{ body }`).\r\n * @param id Source file id for warnings.\r\n */\r\n static #runProgram({body}: Program, id: string): void\r\n {\r\n for (let i = 0, max = body.length; i < max; i++)\r\n {\r\n const NODE = body[i]\r\n\r\n if (NODE.type === 'ExpressionStatement') Vue[check](NODE.expression, false, id)\r\n }\r\n }\r\n\r\n // ##ANALYZERS\r\n /**\r\n * Parses a Vue single-file component and registers the class tokens of its `<template>` block.\r\n * Components without a template are ignored.\r\n * @param code Full `.vue` file source.\r\n * @param id Source file id, used in warnings.\r\n */\r\n static override analyze(code: string, id: string): void\r\n {\r\n const TEMPLATE = parse(code).descriptor.template?.content\r\n\r\n if (TEMPLATE) Vue.#checkNode(baseParse(TEMPLATE), id) // baseParse attend du HTML de template (sans <template> wrapper)\r\n }\r\n\r\n // ##UTILS\r\n /**\r\n * Classifies a `:class` / class-identifier binding: plain string literals go to `run`; otherwise Meriyah parses\r\n * the expression (as `(…)`) and `check` walks the AST (templates, arrays, objects, conditionals, …).\r\n * Expressions shorter than two characters are ignored.\r\n * @param expression Expression content from a directive (trimmed here).\r\n * @param id Source file id for warnings.\r\n */\r\n static #checkExpression(expression: string, id: string): void\r\n {\r\n const EXPRESSION = expression.trim()\r\n\r\n if (EXPRESSION.length > 1) Vue.#isLiteral(EXPRESSION)\r\n ? Vue[run](EXPRESSION.slice(1, -1), id)\r\n // *Wrap in (...) so `{ class: … }` / `{ 'pa:1rem': … }` parse as ObjectExpression, not a block.\r\n : Vue.#runProgram(parseScript(`(${EXPRESSION})`, { next: true }) as Program, id)\r\n }\r\n\r\n /**\r\n * Walks a `v-bind=\"{ … }\"` / attribute-identifier object via Meriyah + `runProperties(…, false)`:\r\n * values of {@link Classter.CLASS_IDENTIFIERS} are analyzed as class expressions; values of\r\n * {@link Classter.ATTRIBUTES_IDENTIFIERS} that are object literals are recursed into. Non-object expressions are ignored.\r\n * @param object Expression expected to be an object literal.\r\n * @param id Source file id for warnings.\r\n */\r\n static #checkVBindObject(object: string, id: string): void\r\n {\r\n const OBJECT = object.trim()\r\n\r\n if (!Vue.#isObject(OBJECT)) return\r\n\r\n const NODE = (parseScript(`(${OBJECT})`, { next: true }) as Program).body[0]\r\n\r\n if (NODE?.type === 'ExpressionStatement' && NODE.expression.type === 'ObjectExpression') Vue[runProperties](NODE.expression.properties, false, id)\r\n }\r\n\r\n /**\r\n * Dispatches a template AST node (root, element, `v-if`, `v-for`, …).\r\n * @param node Template node to inspect.\r\n * @param id Source file id for warnings.\r\n */\r\n static #checkNode(node: RootNode | TemplateChildNode, id: string): void\r\n {\r\n switch (node.type)\r\n {\r\n case NodeTypes.ROOT:\r\n Vue.#runChildren(node.children, id)\r\n break\r\n case NodeTypes.ELEMENT:\r\n Vue.#runProps(node.props, id)\r\n Vue.#runChildren(node.children, id)\r\n break\r\n case NodeTypes.IF:\r\n Vue.#runIf(node.branches, id)\r\n break\r\n case NodeTypes.FOR:\r\n Vue.#runChildren(node.children, id)\r\n break\r\n default:\r\n }\r\n }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Vue"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import { Plugin as Plugin$1 } from 'vite';
2
2
  import { Up } from '../index.js';
3
3
  import { P as Plugin } from '../index-ymMzfIlh.js';
4
- import { C as Classter } from '../Classter-BvYgmPAa.js';
4
+ import { C as Classter } from '../Classter-DZavFSTW.js';
5
5
  import '../symbols/index.js';
6
6
  import '../Wait-C8AD49l9.js';
7
7
  import '../index-BlwaDpQl.js';
@@ -219,8 +219,11 @@ declare namespace Vite {
219
219
  * The plugin:
220
220
  * - Replaces every `import Up from 'upwwwards'` with a virtual module that constructs `Up` exactly once
221
221
  * (on the server and in the browser) with the `up` config, the selected adapter and the enabled plugins.
222
- * - Sets `resolve.dedupe` and `optimizeDeps.exclude` / `ssr.optimizeDeps.exclude` for the package surface so
223
- * Vite never prebundles a second copy of `Up` while plugins still import `../core/Up.js` (dual-runtime hazard).
222
+ * That virtual module loads the class via `upwwwards/core/Up` so Nitro/Rolldown cannot collapse a self-import
223
+ * into `undefined[Symbol(upwwwards::construct)]` during SSR.
224
+ * - Sets `resolve.dedupe`, `optimizeDeps.exclude` / `ssr.optimizeDeps.exclude`, and `ssr.noExternal: ['upwwwards']`
225
+ * so Vite never prebundles a second copy of `Up` while plugins still import `../core/Up.js`, and so SSR keeps
226
+ * the virtual `construct` entry in the server graph.
224
227
  * - Writes generated files into `<setupIn>/upwwwards/` at build start: `private/types/upwwwards.d.ts`
225
228
  * (types of `Up.Adapter`, the enabled plugins, `AdapterConfig` / `AdapterRef` and `EventData`; rewritten when outdated),
226
229
  * `customizable/types/config.d.ts` (created once, then yours to edit, to augment `AppCache` and plugin interfaces),
@@ -2,8 +2,9 @@ import fs, { readdirSync, readFileSync } from "fs";
2
2
  import { fileURLToPath } from "url";
3
3
  import path from "path";
4
4
  import Logs from "../scripts/Logs.js";
5
- const FOLDER_NAME = "upwwwards", CUSTOMIZABLE_FOLDER_NAME = "customizable", PRIVATE_FOLDER_NAME = "private", ID = "upwwwards", VIRTUAL_ID = `\0virtual::${ID}::`, CLASSTER_ID = "classter.css", VIRTUAL_CLASSTER_ID = `\0virtual::${CLASSTER_ID}`, CLASSTER_MARK = "[data-upwwwards-classter]", CLASSTER_MARK_STYLE = `${CLASSTER_MARK}{display:contents}`, CLASSTER_MARK_RGX = new RegExp(`\\${CLASSTER_MARK}\\s*{\\s*display\\s*:\\s*contents\\s*;?\\s*}\\s*`), OPTIMIZE_DEPS_EXCLUDE = [
5
+ const FOLDER_NAME = "upwwwards", CUSTOMIZABLE_FOLDER_NAME = "customizable", PRIVATE_FOLDER_NAME = "private", ID = "upwwwards", UP_CORE_ID = `${ID}/core/Up`, VIRTUAL_ID = `\0virtual::${ID}::`, CLASSTER_ID = "classter.css", VIRTUAL_CLASSTER_ID = `\0virtual::${CLASSTER_ID}`, CLASSTER_MARK = "[data-upwwwards-classter]", CLASSTER_MARK_STYLE = `${CLASSTER_MARK}{display:contents}`, CLASSTER_MARK_RGX = new RegExp(`\\${CLASSTER_MARK}\\s*{\\s*display\\s*:\\s*contents\\s*;?\\s*}\\s*`), OPTIMIZE_DEPS_EXCLUDE = [
6
6
  ID,
7
+ `${ID}/core/Up`,
7
8
  `${ID}/contexts/nuxt`,
8
9
  `${ID}/contexts/sveltekit`,
9
10
  `${ID}/adapters`,
@@ -334,7 +335,10 @@ function config() {
334
335
  server: { watch: { ignored: [`**/${FOLDER_NAME}/${PRIVATE_FOLDER_NAME}/**`] } },
335
336
  resolve: { dedupe: [ID] },
336
337
  optimizeDeps: { exclude: [...OPTIMIZE_DEPS_EXCLUDE] },
337
- ssr: { optimizeDeps: { exclude: [...OPTIMIZE_DEPS_EXCLUDE] } }
338
+ ssr: {
339
+ noExternal: [ID],
340
+ optimizeDeps: { exclude: [...OPTIMIZE_DEPS_EXCLUDE] }
341
+ }
338
342
  };
339
343
  }
340
344
  function configResolved(config2) {
@@ -367,7 +371,7 @@ async function resolveID(id) {
367
371
  }
368
372
  }
369
373
  function load(id) {
370
- return id.startsWith(VIRTUAL_ID) ? `import Up from '${id.substring(VIRTUAL_ID.length)}'; ${this.virtual}` : this.Classter && id === VIRTUAL_CLASSTER_ID ? dev ? this.Classter.get() : CLASSTER_MARK_STYLE : null;
374
+ return id.startsWith(VIRTUAL_ID) ? `import Up from '${UP_CORE_ID}'; ${this.virtual}` : this.Classter && id === VIRTUAL_CLASSTER_ID ? dev ? this.Classter.get() : CLASSTER_MARK_STYLE : null;
371
375
  }
372
376
  function buildStart() {
373
377
  if (this.Classter) readHTMLFiles(this);