Brunobkr/llama.cpp_AlgMor24_github
ΩFFFΣLLIa • llama.cpp • AlgMor24 ██████╗ ███████╗███████╗███████╗██╗ ██╗ ██╗ █████╗ ██╔═══██╗██╔════╝██╔════╝██╔════╝██║ ██║ ██║██╔══██╗ ██║ ██║█████╗ █████╗ █████╗ ██║ ██║ ██║███████║ ██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██║██╔══██║ ╚██████╔╝██║ ██║ ███████╗███████╗███████╗██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝╚═╝ ╚═╝ High-Performance LLM / VLM Inference & Autonomous Agentic Ecosystem… See the full description on the dataset page: https://huggingface.co/datasets/Brunobkr/llama.cpp_AlgMor24_github.
03.1k
1/** @import { VariableDeclarator, Node, Identifier, AssignmentExpression, LabeledStatement, ExpressionStatement } from 'estree' */2/** @import { Visitors } from 'zimmerframe' */3/** @import { ComponentAnalysis } from '../phases/types.js' */4/** @import { Scope } from '../phases/scope.js' */5/** @import { AST, Binding, ValidatedCompileOptions } from '#compiler' */6import MagicString from 'magic-string';7import { walk } from 'zimmerframe';8import { parse } from '../phases/1-parse/index.js';9import { regex_valid_component_name } from '../phases/1-parse/state/element.js';10import { analyze_component } from '../phases/2-analyze/index.js';11import { get_rune } from '../phases/scope.js';12import { reset, UNKNOWN_FILENAME } from '../state.js';13import {14 extract_identifiers,15 extract_all_identifiers_from_expression,16 is_text_attribute17} from '../utils/ast.js';18import { migrate_svelte_ignore } from '../utils/extract_svelte_ignore.js';19import { validate_component_options } from '../validate-options.js';20import { is_reserved, is_svg, is_void } from '../../utils.js';21import { regex_is_valid_identifier } from '../phases/patterns.js';22 23const regex_style_tags = /(<style[^>]+>)([\S\s]*?)(<\/style>)/g;24const style_placeholder = '/*$$__STYLE_CONTENT__$$*/';25 26let has_migration_task = false;27 28class MigrationError extends Error {29 /**30 * @param {string} msg31 */32 constructor(msg) {33 super(msg);34 }35}36 37/**38 *39 * @param {State} state40 */41function migrate_css(state) {42 if (!state.analysis.css.ast?.start) return;43 const css_contents = state.str44 .snip(state.analysis.css.ast.start, /** @type {number} */ (state.analysis.css.ast?.end))45 .toString();46 let code = css_contents;47 let starting = 0;48 49 // since we already blank css we can't work directly on `state.str` so we will create a copy that we can update50 const str = new MagicString(code);51 while (code) {52 if (53 code.startsWith(':has') ||54 code.startsWith(':is') ||55 code.startsWith(':where') ||56 code.startsWith(':not')57 ) {58 let start = code.indexOf('(') + 1;59 let is_global = false;60 61 const global_str = ':global';62 const next_global = code.indexOf(global_str);63 const str_between = code.substring(start, next_global);64 if (!str_between.trim()) {65 is_global = true;66 start += global_str.length;67 } else {68 const prev_global = css_contents.lastIndexOf(global_str, starting);69 if (prev_global > -1) {70 const end =71 find_closing_parenthesis(css_contents.indexOf('(', prev_global) + 1, css_contents) -72 starting;73 if (end > start) {74 starting += end;75 code = code.substring(end);76 continue;77 }78 }79 }80 81 const end = find_closing_parenthesis(start, code);82 if (start && end) {83 if (!is_global && !code.startsWith(':not')) {84 str.prependLeft(starting + start, ':global(');85 str.appendRight(starting + end - 1, ')');86 }87 starting += end - 1;88 code = code.substring(end - 1);89 continue;90 }91 }92 starting++;93 code = code.substring(1);94 }95 state.str.update(state.analysis.css.ast?.start, state.analysis.css.ast?.end, str.toString());96}97 98/**99 * @param {number} start100 * @param {string} code101 */102function find_closing_parenthesis(start, code) {103 let parenthesis = 1;104 let end = start;105 let char = code[end];106 // find the closing parenthesis107 while (parenthesis !== 0 && char) {108 if (char === '(') parenthesis++;109 if (char === ')') parenthesis--;110 end++;111 char = code[end];112 }113 return end;114}115 116/**117 * Does a best-effort migration of Svelte code towards using runes, event attributes and render tags.118 * May throw an error if the code is too complex to migrate automatically.119 *120 * @param {string} source121 * @param {{ filename?: string, use_ts?: boolean }} [options]122 * @returns {{ code: string; }}123 */124export function migrate(source, { filename, use_ts } = {}) {125 let og_source = source;126 try {127 has_migration_task = false;128 // Blank CSS, could contain SCSS or similar that needs a preprocessor.129 // Since we don't care about CSS in this migration, we'll just ignore it.130 /** @type {Array<[number, string]>} */131 const style_contents = [];132 source = source.replace(regex_style_tags, (_, start, content, end, idx) => {133 style_contents.push([idx + start.length, content]);134 return start + style_placeholder + end;135 });136 137 reset({ warning: () => false, filename });138 139 let parsed = parse(source);140 141 const { customElement: customElementOptions, ...parsed_options } = parsed.options || {};142 143 /** @type {ValidatedCompileOptions} */144 const combined_options = {145 ...validate_component_options({}, ''),146 ...parsed_options,147 customElementOptions,148 filename: filename ?? UNKNOWN_FILENAME,149 css: 'css' in parsed_options ? () => parsed_options.css ?? 'external' : () => 'external',150 runes: 'runes' in parsed_options ? () => parsed_options.runes : () => undefined,151 experimental: {152 async: true153 }154 };155 156 const str = new MagicString(source);157 const analysis = analyze_component(parsed, source, combined_options);158 const indent = guess_indent(source);159 160 str.replaceAll(/(<svelte:options\s.*?\s?)accessors\s?/g, (_, $1) => $1);161 162 for (const content of style_contents) {163 str.overwrite(content[0], content[0] + style_placeholder.length, content[1]);164 }165 166 /** @type {State} */167 let state = {168 scope: analysis.instance.scope,169 analysis,170 filename,171 str,172 indent,173 props: [],174 props_insertion_point: parsed.instance?.content.start ?? 0,175 has_props_rune: false,176 has_type_or_fallback: false,177 end: source.length,178 names: {179 props: analysis.root.unique('props').name,180 rest: analysis.root.unique('rest').name,181 182 // event stuff183 run: analysis.root.unique('run').name,184 handlers: analysis.root.unique('handlers').name,185 stopImmediatePropagation: analysis.root.unique('stopImmediatePropagation').name,186 preventDefault: analysis.root.unique('preventDefault').name,187 stopPropagation: analysis.root.unique('stopPropagation').name,188 once: analysis.root.unique('once').name,189 self: analysis.root.unique('self').name,190 trusted: analysis.root.unique('trusted').name,191 createBubbler: analysis.root.unique('createBubbler').name,192 bubble: analysis.root.unique('bubble').name,193 passive: analysis.root.unique('passive').name,194 nonpassive: analysis.root.unique('nonpassive').name195 },196 legacy_imports: new Set(),197 script_insertions: new Set(),198 derived_components: new Map(),199 derived_conflicting_slots: new Map(),200 derived_labeled_statements: new Set(),201 has_svelte_self: false,202 uses_ts:203 // Some people could use jsdoc but have a tsconfig.json, so double-check file for jsdoc indicators204 (use_ts && !source.includes('@type {')) ||205 !!parsed.instance?.attributes.some(206 (attr) => attr.name === 'lang' && /** @type {any} */ (attr).value[0].data === 'ts'207 )208 };209 210 if (parsed.module) {211 const context = parsed.module.attributes.find((attr) => attr.name === 'context');212 if (context) {213 state.str.update(context.start, context.end, 'module');214 }215 }216 217 if (parsed.instance) {218 walk(parsed.instance.content, state, instance_script);219 }220 221 state = { ...state, scope: analysis.template.scope };222 walk(parsed.fragment, state, template);223 224 let insertion_point = parsed.instance225 ? /** @type {number} */ (parsed.instance.content.start)226 : 0;227 228 const need_script =229 state.legacy_imports.size > 0 ||230 state.derived_components.size > 0 ||231 state.derived_conflicting_slots.size > 0 ||232 state.script_insertions.size > 0 ||233 state.props.length > 0 ||234 analysis.uses_rest_props ||235 analysis.uses_props ||236 state.has_svelte_self;237 238 const need_ts_tag =239 state.uses_ts &&240 (!parsed.instance || !parsed.instance.attributes.some((attr) => attr.name === 'lang'));241 242 if (!parsed.instance && need_script) {243 str.appendRight(0, need_ts_tag ? '<script lang="ts">' : '<script>');244 }245 246 if (state.has_svelte_self && filename) {247 const file = filename.split('/').pop();248 str.appendRight(249 insertion_point,250 `\n${indent}import ${state.analysis.name} from './${file}';`251 );252 }253 254 const specifiers = [...state.legacy_imports].map((imported) => {255 const local = state.names[imported];256 return imported === local ? imported : `${imported} as ${local}`;257 });258 259 const legacy_import = `import { ${specifiers.join(', ')} } from 'svelte/legacy';\n`;260 261 if (state.legacy_imports.size > 0) {262 str.appendRight(insertion_point, `\n${indent}${legacy_import}`);263 }264 265 if (state.script_insertions.size > 0) {266 str.appendRight(267 insertion_point,268 `\n${indent}${[...state.script_insertions].join(`\n${indent}`)}`269 );270 }271 272 insertion_point = state.props_insertion_point;273 274 /**275 * @param {"derived"|"props"|"bindable"} rune276 */277 function check_rune_binding(rune) {278 const has_rune_binding = !!state.scope.get(rune);279 if (has_rune_binding) {280 throw new MigrationError(281 `migrating this component would require adding a \`$${rune}\` rune but there's already a variable named ${rune}.\n Rename the variable and try again or migrate by hand.`282 );283 }284 }285 286 if (state.props.length > 0 || analysis.uses_rest_props || analysis.uses_props) {287 const has_many_props = state.props.length > 3;288 const newline_separator = `\n${indent}${indent}`;289 const props_separator = has_many_props ? newline_separator : ' ';290 let props = '';291 if (analysis.uses_props) {292 props = `...${state.names.props}`;293 } else {294 props = state.props295 .filter((prop) => !prop.type_only)296 .map((prop) => {297 let prop_str =298 prop.local === prop.exported ? prop.local : `${prop.exported}: ${prop.local}`;299 if (prop.bindable) {300 check_rune_binding('bindable');301 prop_str += ` = $bindable(${prop.init})`;302 } else if (prop.init) {303 prop_str += ` = ${prop.init}`;304 }305 return prop_str;306 })307 .join(`,${props_separator}`);308 309 if (analysis.uses_rest_props) {310 props += `${state.props.length > 0 ? `,${props_separator}` : ''}...${state.names.rest}`;311 }312 }313 314 if (state.has_props_rune) {315 // some render tags or forwarded event attributes to add316 str.appendRight(insertion_point, ` ${props},`);317 } else {318 const type_name = state.scope.root.unique('Props').name;319 let type = '';320 321 // Try to infer when we don't want to add types (e.g. user doesn't use types, or this is a zero-types +page.svelte)322 if (state.has_type_or_fallback || state.props.every((prop) => prop.slot_name)) {323 if (state.uses_ts) {324 type = `interface ${type_name} {${newline_separator}${state.props325 .map((prop) => {326 const comment = prop.comment ? `${prop.comment}${newline_separator}` : '';327 return `${comment}${prop.exported}${prop.optional ? '?' : ''}: ${prop.type};${prop.trailing_comment ? ' ' + prop.trailing_comment : ''}`;328 })329 .join(newline_separator)}`;330 if (analysis.uses_props || analysis.uses_rest_props) {331 type += `${state.props.length > 0 ? newline_separator : ''}[key: string]: any`;332 }333 type += `\n${indent}}`;334 } else {335 type = `/**\n${indent} * @typedef {Object} ${type_name}${state.props336 .map((prop) => {337 return `\n${indent} * @property {${prop.type}} ${prop.optional ? `[${prop.exported}]` : prop.exported}${prop.comment ? ` - ${prop.comment}` : ''}${prop.trailing_comment ? ` - ${prop.trailing_comment.trim()}` : ''}`;338 })339 .join(``)}\n${indent} */`;340 }341 }342 343 let props_declaration = `let {${props_separator}${props}${has_many_props ? `\n${indent}` : ' '}}`;344 if (state.uses_ts) {345 if (type) {346 props_declaration = `${type}\n\n${indent}${props_declaration}`;347 }348 check_rune_binding('props');349 props_declaration = `${props_declaration}${type ? `: ${type_name}` : ''} = $props();`;350 } else {351 if (type) {352 props_declaration = `${state.props.length > 0 ? `${type}\n\n${indent}` : ''}/** @type {${state.props.length > 0 ? type_name : ''}${analysis.uses_props || analysis.uses_rest_props ? `${state.props.length > 0 ? ' & ' : ''}{ [key: string]: any }` : ''}} */\n${indent}${props_declaration}`;353 }354 check_rune_binding('props');355 props_declaration = `${props_declaration} = $props();`;356 }357 358 props_declaration = `\n${indent}${props_declaration}`;359 str.appendRight(insertion_point, props_declaration);360 }361 362 if (parsed.instance && need_ts_tag) {363 str.appendRight(parsed.instance.start + '<script'.length, ' lang="ts"');364 }365 }366 367 /**368 * If true, then we need to move all reactive statements to the end of the script block,369 * in their correct order. Svelte 4 reordered reactive statements, $derived/$effect.pre370 * don't have this behavior.371 */372 let needs_reordering = false;373 374 for (const [node, { dependencies }] of state.analysis.reactive_statements) {375 /** @type {Binding[]} */376 let ids = [];377 if (378 node.body.type === 'ExpressionStatement' &&379 node.body.expression.type === 'AssignmentExpression'380 ) {381 ids = extract_identifiers(node.body.expression.left)382 .map((id) => state.scope.get(id.name))383 .filter((id) => !!id);384 }385 386 if (387 dependencies.some(388 (dep) =>389 !ids.includes(dep) &&390 (dep.kind === 'prop' || dep.kind === 'bindable_prop'391 ? state.props_insertion_point392 : /** @type {number} */ (dep.node.start)) > /** @type {number} */ (node.start)393 )394 ) {395 needs_reordering = true;396 break;397 }398 }399 400 if (needs_reordering) {401 const nodes = Array.from(state.analysis.reactive_statements.keys());402 for (const node of nodes) {403 const { start, end } = get_node_range(source, node);404 str.appendLeft(end, '\n');405 str.move(start, end, /** @type {number} */ (parsed.instance?.content.end));406 str.update(start - (source[start - 2] === '\r' ? 2 : 1), start, '');407 }408 }409 410 insertion_point = parsed.instance411 ? /** @type {number} */ (parsed.instance.content.end)412 : insertion_point;413 414 if (state.derived_components.size > 0) {415 check_rune_binding('derived');416 str.appendRight(417 insertion_point,418 `\n${indent}${[...state.derived_components.entries()].map(([init, name]) => `const ${name} = $derived(${init});`).join(`\n${indent}`)}\n`419 );420 }421 422 if (state.derived_conflicting_slots.size > 0) {423 check_rune_binding('derived');424 str.appendRight(425 insertion_point,426 `\n${indent}${[...state.derived_conflicting_slots.entries()].map(([name, init]) => `const ${name} = $derived(${init});`).join(`\n${indent}`)}\n`427 );428 }429 430 if (state.props.length > 0 && state.analysis.accessors) {431 str.appendRight(432 insertion_point,433 `\n${indent}export {${state.props.reduce((acc, prop) => (prop.slot_name || prop.type_only ? acc : `${acc}\n${indent}\t${prop.local},`), '')}\n${indent}}\n`434 );435 }436 437 if (!parsed.instance && need_script) {438 str.appendRight(insertion_point, '\n</script>\n\n');439 }440 migrate_css(state);441 return {442 code: str.toString()443 };444 } catch (e) {445 if (!(e instanceof MigrationError)) {446 // eslint-disable-next-line no-console447 console.error('Error while migrating Svelte code', e);448 }449 has_migration_task = true;450 return {451 code: `<!-- @migration-task Error while migrating Svelte code: ${/** @type {any} */ (e).message} -->\n${og_source}`452 };453 } finally {454 if (has_migration_task) {455 // eslint-disable-next-line no-console456 console.log(457 `One or more \`@migration-task\` comments were added to ${filename ? `\`${filename}\`` : "a file (unfortunately we don't know the name)"}, please check them and complete the migration manually.`458 );459 }460 }461}462 463/**464 * @typedef {{465 * scope: Scope;466 * str: MagicString;467 * analysis: ComponentAnalysis;468 * filename?: string;469 * indent: string;470 * props: Array<{ local: string; exported: string; init: string; bindable: boolean; slot_name?: string; optional: boolean; type: string; comment?: string; trailing_comment?: string; type_only?: boolean; needs_refine_type?: boolean; }>;471 * props_insertion_point: number;472 * has_props_rune: boolean;473 * has_type_or_fallback: boolean;474 * end: number;475 * names: Record<string, string>;476 * legacy_imports: Set<string>;477 * script_insertions: Set<string>;478 * derived_components: Map<string, string>;479 * derived_conflicting_slots: Map<string, string>;480 * derived_labeled_statements: Set<LabeledStatement>;481 * has_svelte_self: boolean;482 * uses_ts: boolean;483 * }} State484 */485 486/** @type {Visitors<AST.SvelteNode, State>} */487const instance_script = {488 _(node, { state, next }) {489 // @ts-expect-error490 const comments = node.leadingComments;491 if (comments) {492 for (const comment of comments) {493 if (comment.type === 'Line') {494 const migrated = migrate_svelte_ignore(comment.value);495 if (migrated !== comment.value) {496 state.str.overwrite(comment.start + '//'.length, comment.end, migrated);497 }498 }499 }500 }501 next();502 },503 Identifier(node, { state, path }) {504 handle_identifier(node, state, path);505 },506 ImportDeclaration(node, { state }) {507 state.props_insertion_point = node.end ?? state.props_insertion_point;508 if (node.source.value === 'svelte') {509 let illegal_specifiers = [];510 let removed_specifiers = 0;511 for (let specifier of node.specifiers) {512 if (513 specifier.type === 'ImportSpecifier' &&514 specifier.imported.type === 'Identifier' &&515 ['beforeUpdate', 'afterUpdate'].includes(specifier.imported.name)516 ) {517 const references = state.scope.references.get(specifier.local.name);518 if (!references) {519 let end = /** @type {number} */ (520 state.str.original.indexOf(',', specifier.end) !== -1 &&521 state.str.original.indexOf(',', specifier.end) <522 state.str.original.indexOf('}', specifier.end)523 ? state.str.original.indexOf(',', specifier.end) + 1524 : specifier.end525 );526 while (state.str.original[end].trim() === '') end++;527 state.str.remove(/** @type {number} */ (specifier.start), end);528 removed_specifiers++;529 continue;530 }531 illegal_specifiers.push(specifier.imported.name);532 }533 }534 if (removed_specifiers === node.specifiers.length) {535 state.str.remove(/** @type {number} */ (node.start), /** @type {number} */ (node.end));536 }537 if (illegal_specifiers.length > 0) {538 throw new MigrationError(539 `Can't migrate code with ${illegal_specifiers.join(' and ')}. Please migrate by hand.`540 );541 }542 }543 },544 ExportNamedDeclaration(node, { state, next }) {545 if (node.declaration) {546 next();547 return;548 }549 550 let count_removed = 0;551 for (const specifier of node.specifiers) {552 if (specifier.local.type !== 'Identifier') continue;553 554 const binding = state.scope.get(specifier.local.name);555 if (binding?.kind === 'bindable_prop') {556 state.str.remove(557 /** @type {number} */ (specifier.start),558 /** @type {number} */ (specifier.end)559 );560 count_removed++;561 }562 }563 if (count_removed === node.specifiers.length) {564 state.str.remove(/** @type {number} */ (node.start), /** @type {number} */ (node.end));565 }566 },567 VariableDeclaration(node, { state, path, visit, next }) {568 if (state.scope !== state.analysis.instance.scope) {569 return;570 }571 572 let nr_of_props = 0;573 574 for (let i = 0; i < node.declarations.length; i++) {575 const declarator = node.declarations[i];576 if (state.analysis.runes) {577 if (get_rune(declarator.init, state.scope) === '$props') {578 state.props_insertion_point = /** @type {number} */ (declarator.id.start) + 1;579 state.has_props_rune = true;580 }581 continue;582 }583 584 let bindings;585 try {586 bindings = state.scope.get_bindings(declarator);587 } catch (e) {588 // no bindings, so we can skip this589 next();590 continue;591 }592 const has_state = bindings.some((binding) => binding.kind === 'state');593 const has_props = bindings.some((binding) => binding.kind === 'bindable_prop');594 595 if (!has_state && !has_props) {596 next();597 continue;598 }599 600 if (has_props) {601 nr_of_props++;602 603 if (declarator.id.type !== 'Identifier') {604 // TODO invest time in this?605 throw new MigrationError(606 'Encountered an export declaration pattern that is not supported for automigration.'607 );608 // Turn export let into props. It's really really weird because export let { x: foo, z: [bar]} = ..609 // means that foo and bar are the props (i.e. the leaves are the prop names), not x and z.610 // const tmp = b.id(state.scope.generate('tmp'));611 // const paths = extract_paths(declarator.id, tmp);612 // state.props_pre.push(613 // b.declaration('const', tmp, visit(declarator.init!) as Expression)614 // );615 // for (const path of paths) {616 // const name = (path.node as Identifier).name;617 // const binding = state.scope.get(name)!;618 // const value = path.expression;619 // if (binding.kind === 'bindable_prop' || binding.kind === 'rest_prop') {620 // state.props.push({621 // local: name,622 // exported: binding.prop_alias ? binding.prop_alias : name,623 // init: value624 // });625 // state.props_insertion_point = /** @type {number} */(declarator.end);626 // } else {627 // declarations.push(b.declarator(path.node, value));628 // }629 // }630 }631 632 const name = declarator.id.name;633 const binding = /** @type {Binding} */ (state.scope.get(name));634 635 if (state.analysis.uses_props && (declarator.init || binding.updated)) {636 throw new MigrationError(637 '$$props is used together with named props in a way that cannot be automatically migrated.'638 );639 }640 641 const prop = state.props.find((prop) => prop.exported === (binding.prop_alias || name));642 if (prop) {643 next();644 // $$Props type was used645 prop.init = declarator.init646 ? state.str647 .snip(648 /** @type {number} */ (declarator.init.start),649 /** @type {number} */ (declarator.init.end)650 )651 .toString()652 : '';653 prop.bindable = binding.updated;654 prop.exported = binding.prop_alias || name;655 prop.type_only = false;656 } else {657 next();658 state.props.push({659 local: name,660 exported: binding.prop_alias ? binding.prop_alias : name,661 init: declarator.init662 ? state.str663 .snip(664 /** @type {number} */ (declarator.init.start),665 /** @type {number} */ (declarator.init.end)666 )667 .toString()668 : '',669 optional: !!declarator.init,670 bindable: binding.updated,671 ...extract_type_and_comment(declarator, state, path)672 });673 }674 675 let start = /** @type {number} */ (declarator.start);676 let end = /** @type {number} */ (declarator.end);677 678 // handle cases like let a,b,c; where only some are exported679 if (node.declarations.length > 1) {680 // move the insertion point after the node itself;681 state.props_insertion_point = /** @type {number} */ (node.end);682 // if it's not the first declaration remove from the , of the previous declaration683 if (i !== 0) {684 start = state.str.original.indexOf(685 ',',686 /** @type {number} */ (node.declarations[i - 1].end)687 );688 }689 // if it's not the last declaration remove either from up until the690 // start of the next declaration (if it's the first declaration) or691 // up until the last index of , from the next declaration692 if (i !== node.declarations.length - 1) {693 if (i === 0) {694 end = /** @type {number} */ (node.declarations[i + 1].start);695 } else {696 end = state.str.original.lastIndexOf(697 ',',698 /** @type {number} */ (node.declarations[i + 1].start)699 );700 }701 }702 } else {703 state.props_insertion_point = /** @type {number} */ (declarator.end);704 }705 706 state.str.update(start, end, '');707 708 continue;709 }710 711 /**712 * @param {"state"|"derived"} rune713 */714 function check_rune_binding(rune) {715 const has_rune_binding = !!state.scope.get(rune);716 if (has_rune_binding) {717 throw new MigrationError(718 `can't migrate \`${state.str.original.substring(/** @type {number} */ (node.start), node.end)}\` to \`$${rune}\` because there's a variable named ${rune}.\n Rename the variable and try again or migrate by hand.`719 );720 }721 }722 723 // state724 if (declarator.init) {725 let { start, end } = /** @type {{ start: number, end: number }} */ (declarator.init);726 727 if (declarator.init.type === 'SequenceExpression') {728 while (state.str.original[start] !== '(') start -= 1;729 while (state.str.original[end - 1] !== ')') end += 1;730 }731 732 check_rune_binding('state');733 734 state.str.prependLeft(start, '$state(');735 state.str.appendRight(end, ')');736 } else {737 /**738 * @type {AssignmentExpression | undefined}739 */740 let assignment_in_labeled;741 /**742 * @type {LabeledStatement | undefined}743 */744 let labeled_statement;745 746 // Analyze declaration bindings to see if they're exclusively updated within a single reactive statement747 const possible_derived = bindings.every((binding) =>748 binding.references.every((reference) => {749 const declaration = reference.path.find((el) => el.type === 'VariableDeclaration');750 const assignment = reference.path.find((el) => el.type === 'AssignmentExpression');751 const update = reference.path.find((el) => el.type === 'UpdateExpression');752 const labeled = /** @type {LabeledStatement | undefined} */ (753 reference.path.find((el) => el.type === 'LabeledStatement' && el.label.name === '$')754 );755 756 if (757 assignment &&758 labeled &&759 // ensure that $: foo = bar * 2 is not counted as a reassignment of bar760 (labeled.body.type !== 'ExpressionStatement' ||761 labeled.body.expression !== assignment ||762 (assignment.left.type === 'Identifier' &&763 assignment.left.name === binding.node.name))764 ) {765 if (assignment_in_labeled) return false;766 assignment_in_labeled = /** @type {AssignmentExpression} */ (assignment);767 labeled_statement = labeled;768 }769 770 return (771 !update &&772 ((declaration && binding.initial) ||773 (labeled && assignment) ||774 (!labeled && !assignment))775 );776 })777 );778 779 const labeled_has_single_assignment =780 labeled_statement?.body.type === 'BlockStatement' &&781 labeled_statement.body.body.length === 1 &&782 labeled_statement.body.body[0].type === 'ExpressionStatement';783 784 const is_expression_assignment =785 labeled_statement?.body.type === 'ExpressionStatement' &&786 labeled_statement.body.expression.type === 'AssignmentExpression';787 788 let should_be_state = false;789 790 if (is_expression_assignment) {791 const body = /**@type {ExpressionStatement}*/ (labeled_statement?.body);792 const expression = /**@type {AssignmentExpression}*/ (body.expression);793 const [, ids] = extract_all_identifiers_from_expression(expression.right);794 if (ids.length === 0) {795 should_be_state = true;796 state.derived_labeled_statements.add(797 /** @type {LabeledStatement} */ (labeled_statement)798 );799 }800 }801 802 if (803 !should_be_state &&804 possible_derived &&805 assignment_in_labeled &&806 labeled_statement &&807 (labeled_has_single_assignment || is_expression_assignment)808 ) {809 const indent = state.str.original.substring(810 state.str.original.lastIndexOf('\n', /** @type {number} */ (node.start)) + 1,811 /** @type {number} */ (node.start)812 );813 // transfer all the leading comments814 if (815 labeled_statement.body.type === 'BlockStatement' &&816 labeled_statement.body.body[0].leadingComments817 ) {818 for (let comment of labeled_statement.body.body[0].leadingComments) {819 state.str.prependLeft(820 /** @type {number} */ (node.start),821 comment.type === 'Block'822 ? `/*${comment.value}*/\n${indent}`823 : `// ${comment.value}\n${indent}`824 );825 }826 }827 828 check_rune_binding('derived');829 830 // Someone wrote a `$: { ... }` statement which we can turn into a `$derived`831 state.str.appendRight(832 /** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),833 ' = $derived('834 );835 visit(assignment_in_labeled.right);836 state.str.appendRight(837 /** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),838 state.str839 .snip(840 /** @type {number} */ (assignment_in_labeled.right.start),841 /** @type {number} */ (assignment_in_labeled.right.end)842 )843 .toString()844 );845 state.str.remove(846 /** @type {number} */ (labeled_statement.start),847 /** @type {number} */ (labeled_statement.end)848 );849 state.str.appendRight(850 /** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),851 ')'852 );853 state.derived_labeled_statements.add(labeled_statement);854 855 // transfer all the trailing comments856 if (857 labeled_statement.body.type === 'BlockStatement' &&858 labeled_statement.body.body[0].trailingComments859 ) {860 for (let comment of labeled_statement.body.body[0].trailingComments) {861 state.str.appendRight(862 /** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),863 comment.type === 'Block'864 ? `\n${indent}/*${comment.value}*/`865 : `\n${indent}// ${comment.value}`866 );867 }868 }869 } else {870 check_rune_binding('state');871 872 state.str.prependLeft(873 /** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),874 ' = $state('875 );876 if (should_be_state) {877 // someone wrote a `$: foo = ...` statement which we can turn into `let foo = $state(...)`878 state.str.appendRight(879 /** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),880 state.str881 .snip(882 /** @type {number} */ (883 /** @type {AssignmentExpression} */ (assignment_in_labeled).right.start884 ),885 /** @type {number} */ (886 /** @type {AssignmentExpression} */ (assignment_in_labeled).right.end887 )888 )889 .toString()890 );891 state.str.remove(892 /** @type {number} */ (/** @type {LabeledStatement} */ (labeled_statement).start),893 /** @type {number} */ (/** @type {LabeledStatement} */ (labeled_statement).end)894 );895 }896 state.str.appendRight(897 /** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),898 ')'899 );900 }901 }902 }903 904 if (nr_of_props === node.declarations.length) {905 let start = /** @type {number} */ (node.start);906 let end = /** @type {number} */ (node.end);907 908 const parent = path.at(-1);909 if (parent?.type === 'ExportNamedDeclaration') {910 start = /** @type {number} */ (parent.start);911 end = /** @type {number} */ (parent.end);912 }913 while (state.str.original[start] !== '\n') start--;914 while (state.str.original[end] !== '\n') end++;915 state.str.update(start, end, '');916 }917 },918 BreakStatement(node, { state, path }) {919 if (path[1].type !== 'LabeledStatement') return;920 if (node.label?.name !== '$') return;921 state.str.update(922 /** @type {number} */ (node.start),923 /** @type {number} */ (node.end),924 'return;'925 );926 },927 LabeledStatement(node, { path, state, next }) {928 if (state.analysis.runes) return;929 if (path.length > 1) return;930 if (node.label.name !== '$') return;931 if (state.derived_labeled_statements.has(node)) return;932 933 next();934 935 /**936 * @param {"state"|"derived"} rune937 */938 function check_rune_binding(rune) {939 const has_rune_binding = state.scope.get(rune);940 if (has_rune_binding) {941 throw new MigrationError(942 `can't migrate \`$: ${state.str.original.substring(/** @type {number} */ (node.body.start), node.body.end)}\` to \`$${rune}\` because there's a variable named ${rune}.\n Rename the variable and try again or migrate by hand.`943 );944 }945 }946 947 if (948 node.body.type === 'ExpressionStatement' &&949 node.body.expression.type === 'AssignmentExpression'950 ) {951 const { left, right } = node.body.expression;952 953 const ids = extract_identifiers(left);954 const [, expression_ids] = extract_all_identifiers_from_expression(right);955 const bindings = ids.map((id) => /** @type {Binding} */ (state.scope.get(id.name)));956 957 if (bindings.every((b) => b.kind === 'legacy_reactive')) {958 if (959 right.type !== 'Literal' &&960 bindings.every((b) => b.kind !== 'store_sub') &&961 left.type !== 'MemberExpression'962 ) {963 let { start, end } = /** @type {{ start: number, end: number }} */ (right);964 965 check_rune_binding('derived');966 967 // $derived968 state.str.update(969 /** @type {number} */ (node.start),970 /** @type {number} */ (node.body.expression.start),971 'let '972 );973 974 if (right.type === 'SequenceExpression') {975 while (state.str.original[start] !== '(') start -= 1;976 while (state.str.original[end - 1] !== ')') end += 1;977 }978 979 state.str.prependRight(start, `$derived(`);980 981 // in a case like `$: ({ a } = b())`, there's already a trailing parenthesis.982 // otherwise, we need to add one983 if (state.str.original[/** @type {number} */ (node.body.start)] !== '(') {984 state.str.appendLeft(end, `)`);985 }986 987 return;988 }989 990 for (const binding of bindings) {991 if (binding.reassigned && (ids.includes(binding.node) || expression_ids.length === 0)) {992 check_rune_binding('state');993 const init =994 binding.kind === 'state'995 ? ' = $state()'996 : expression_ids.length === 0997 ? ` = $state(${state.str.original.substring(/** @type {number} */ (right.start), right.end)})`998 : '';999 // implicitly-declared variable which we need to make explicit1000 state.str.prependLeft(1001 /** @type {number} */ (node.start),1002 `let ${binding.node.name}${init};\n${state.indent}`1003 );1004 }1005 }1006 1007 if (expression_ids.length === 0 && bindings.every((b) => b.kind !== 'store_sub')) {1008 state.str.remove(/** @type {number} */ (node.start), /** @type {number} */ (node.end));1009 return;1010 }1011 }1012 }1013 1014 state.legacy_imports.add('run');1015 const is_block_stmt = node.body.type === 'BlockStatement';1016 const start_end = /** @type {number} */ (node.body.start);1017 // TODO try to find out if we can use $derived.by instead?1018 if (is_block_stmt) {1019 state.str.update(1020 /** @type {number} */ (node.start),1021 start_end + 1,1022 `${state.names.run}(() => {`1023 );1024 const end = /** @type {number} */ (node.body.end);1025 state.str.update(end - 1, end, '});');1026 } else {1027 state.str.update(1028 /** @type {number} */ (node.start),1029 start_end,1030 `${state.names.run}(() => {\n${state.indent}`1031 );1032 state.str.indent(state.indent, {1033 exclude: [1034 [0, /** @type {number} */ (node.body.start)],1035 [/** @type {number} */ (node.body.end), state.end]1036 ]1037 });1038 state.str.appendLeft(/** @type {number} */ (node.end), `\n${state.indent}});`);1039 }1040 }1041};1042 1043/**1044 *1045 * @param {State} state1046 * @param {number} start1047 * @param {number} end1048 */1049function trim_block(state, start, end) {1050 const original = state.str.snip(start, end).toString();1051 const without_parens = original.substring(1, original.length - 1);1052 if (without_parens.trim().length !== without_parens.length) {1053 state.str.update(start + 1, end - 1, without_parens.trim());1054 }1055}1056 1057/** @type {Visitors<AST.SvelteNode, State>} */1058const template = {1059 Identifier(node, { state, path }) {1060 handle_identifier(node, state, path);1061 },1062 RegularElement(node, { state, path, next }) {1063 // Strip off any namespace from the beginning of the node name.1064 const node_name = node.name.replace(/[a-zA-Z-]*:/g, '');1065 1066 if (state.analysis.source[node.end - 2] === '/' && !is_void(node_name) && !is_svg(node_name)) {1067 let trimmed_position = node.end - 2;1068 while (state.str.original.charAt(trimmed_position - 1) === ' ') trimmed_position--;1069 state.str.remove(trimmed_position, node.end - 1);1070 state.str.appendLeft(node.end, `</${node.name}>`);1071 }1072 1073 migrate_slot_usage(node, path, state);1074 handle_events(node, state);1075 1076 next();1077 },1078 SvelteSelf(node, { state, next }) {1079 const source = state.str.original.substring(node.start, node.end);1080 if (!state.filename) {1081 const indent = guess_indent(source);1082 has_migration_task = true;1083 state.str.prependRight(1084 node.start,1085 `<!-- @migration-task: svelte:self is deprecated, import this Svelte file into itself instead -->\n${indent}`1086 );1087 next();1088 return;1089 }1090 // overwrite the open tag1091 state.str.overwrite(1092 node.start + 1,1093 node.start + 1 + 'svelte:self'.length,1094 `${state.analysis.name}`1095 );1096 // if it has a fragment we need to overwrite the closing tag too1097 if (node.fragment.nodes.length > 0) {1098 state.str.overwrite(1099 state.str.original.lastIndexOf('<', node.end) + 2,1100 node.end - 1,1101 `${state.analysis.name}`1102 );1103 } else if (!source.endsWith('/>')) {1104 // special case for case `<svelte:self></svelte:self>` it has no fragment but1105 // we still need to overwrite the end tag1106 state.str.overwrite(1107 node.start + source.lastIndexOf('</', node.end) + 2,1108 node.end - 1,1109 `${state.analysis.name}`1110 );1111 }1112 state.has_svelte_self = true;1113 next();1114 },1115 SvelteElement(node, { state, path, next }) {1116 migrate_slot_usage(node, path, state);1117 if (node.tag.type === 'Literal') {1118 let is_static = true;1119 1120 let a = /** @type {number} */ (node.tag.start);1121 let b = /** @type {number} */ (node.tag.end);1122 let quote_mark = state.str.original[a - 1];1123 1124 while (state.str.original[--a] !== '=') {1125 if (state.str.original[a] === '{') {1126 is_static = false;1127 break;1128 }1129 }1130 1131 if (is_static && state.str.original[b] === quote_mark) {1132 state.str.prependLeft(a + 1, '{');1133 state.str.appendRight(/** @type {number} */ (node.tag.end) + 1, '}');1134 }1135 }1136 1137 handle_events(node, state);1138 next();1139 },1140 Component(node, { state, path, next }) {1141 next();1142 migrate_slot_usage(node, path, state);1143 },1144 SvelteComponent(node, { state, next, path }) {1145 next();1146 1147 migrate_slot_usage(node, path, state);1148 1149 let expression = state.str1150 .snip(1151 /** @type {number} */ (node.expression.start),1152 /** @type {number} */ (node.expression.end)1153 )1154 .toString();1155 1156 if (1157 (node.expression.type !== 'Identifier' && node.expression.type !== 'MemberExpression') ||1158 !regex_valid_component_name.test(expression)1159 ) {1160 let current_expression = expression;1161 expression = state.scope.generate('SvelteComponent');1162 let needs_derived = true;1163 for (let i = path.length - 1; i >= 0; i--) {1164 const part = path[i];1165 if (1166 part.type === 'EachBlock' ||1167 part.type === 'AwaitBlock' ||1168 part.type === 'IfBlock' ||1169 part.type === 'SnippetBlock' ||1170 part.type === 'Component' ||1171 part.type === 'SvelteComponent'1172 ) {1173 let position = node.start;1174 if (i !== path.length - 1) {1175 for (let modifier = 1; modifier < path.length - i; modifier++) {1176 const path_part = path[i + modifier];1177 if ('start' in path_part) {1178 position = /** @type {number} */ (path_part.start);1179 break;1180 }1181 }1182 }1183 const indent = state.str.original.substring(1184 state.str.original.lastIndexOf('\n', position) + 1,1185 position1186 );1187 state.str.appendRight(1188 position,1189 `{@const ${expression} = ${current_expression}}\n${indent}`1190 );1191 needs_derived = false;1192 break;1193 }1194 }1195 if (needs_derived) {1196 if (state.derived_components.has(current_expression)) {1197 expression = /** @type {string} */ (state.derived_components.get(current_expression));1198 } else {1199 state.derived_components.set(current_expression, expression);1200 }