chore: remove references to node.parent

pull/14395/head
Rich Harris 10 months ago
parent dd9abea2a1
commit 9682d573d6

@ -710,7 +710,7 @@ export function analyze_component(root, source, options) {
// mark nodes as scoped/unused/empty etc // mark nodes as scoped/unused/empty etc
for (const element of analysis.elements) { for (const element of analysis.elements) {
prune(analysis.css.ast, element); prune(analysis.css.ast, element.node);
} }
const { comment } = analysis.css.ast.content; const { comment } = analysis.css.ast.content;
@ -724,18 +724,18 @@ export function analyze_component(root, source, options) {
warn_unused(analysis.css.ast); warn_unused(analysis.css.ast);
} }
outer: for (const element of analysis.elements) { outer: for (const { node } of analysis.elements) {
if (element.type === 'RenderTag') continue; if (node.type === 'RenderTag') continue;
if (element.metadata.scoped) { if (node.metadata.scoped) {
// Dynamic elements in dom mode always use spread for attributes and therefore shouldn't have a class attribute added to them // Dynamic elements in dom mode always use spread for attributes and therefore shouldn't have a class attribute added to them
// TODO this happens during the analysis phase, which shouldn't know anything about client vs server // TODO this happens during the analysis phase, which shouldn't know anything about client vs server
if (element.type === 'SvelteElement' && options.generate === 'client') continue; if (node.type === 'SvelteElement' && options.generate === 'client') continue;
/** @type {AST.Attribute | undefined} */ /** @type {AST.Attribute | undefined} */
let class_attribute = undefined; let class_attribute = undefined;
for (const attribute of element.attributes) { for (const attribute of node.attributes) {
if (attribute.type === 'SpreadAttribute') { if (attribute.type === 'SpreadAttribute') {
// The spread method appends the hash to the end of the class attribute on its own // The spread method appends the hash to the end of the class attribute on its own
continue outer; continue outer;
@ -768,7 +768,7 @@ export function analyze_component(root, source, options) {
} }
} }
} else { } else {
element.attributes.push( node.attributes.push(
create_attribute('class', -1, -1, [ create_attribute('class', -1, -1, [
{ {
type: 'Text', type: 'Text',
@ -780,8 +780,8 @@ export function analyze_component(root, source, options) {
} }
]) ])
); );
if (is_custom_element_node(element) && element.attributes.length === 1) { if (is_custom_element_node(node) && node.attributes.length === 1) {
mark_subtree_dynamic(element.metadata.path); mark_subtree_dynamic(node.metadata.path);
} }
} }
} }

@ -9,7 +9,9 @@ import { mark_subtree_dynamic } from './shared/fragment.js';
* @param {Context} context * @param {Context} context
*/ */
export function ExpressionTag(node, context) { export function ExpressionTag(node, context) {
if (node.parent && context.state.parent_element) { const in_attribute = context.path.at(-1)?.type === 'Attribute';
if (!in_attribute && context.state.parent_element) {
if (!is_tag_valid_with_parent('#text', context.state.parent_element)) { if (!is_tag_valid_with_parent('#text', context.state.parent_element)) {
e.node_invalid_placement(node, '`{expression}`', context.state.parent_element); e.node_invalid_placement(node, '`{expression}`', context.state.parent_element);
} }

@ -20,11 +20,11 @@ import { mark_subtree_dynamic } from './shared/fragment.js';
export function RegularElement(node, context) { export function RegularElement(node, context) {
validate_element(node, context); validate_element(node, context);
check_element(node, context.state); check_element(node, context);
node.metadata.path = [...context.path]; node.metadata.path = [...context.path];
context.state.analysis.elements.push(node); context.state.analysis.elements.push({ node, path: context.path });
// Special case: Move the children of <textarea> into a value attribute if they are dynamic // Special case: Move the children of <textarea> into a value attribute if they are dynamic
if (node.name === 'textarea' && node.fragment.nodes.length > 0) { if (node.name === 'textarea' && node.fragment.nodes.length > 0) {

@ -12,7 +12,7 @@ import { mark_subtree_dynamic } from './shared/fragment.js';
export function RenderTag(node, context) { export function RenderTag(node, context) {
validate_opening_tag(node, context.state, '@'); validate_opening_tag(node, context.state, '@');
context.state.analysis.elements.push(node); context.state.analysis.elements.push({ node, path: context.path });
const callee = unwrap_optional(node.expression).callee; const callee = unwrap_optional(node.expression).callee;

@ -13,9 +13,9 @@ import { mark_subtree_dynamic } from './shared/fragment.js';
export function SvelteElement(node, context) { export function SvelteElement(node, context) {
validate_element(node, context); validate_element(node, context);
check_element(node, context.state); check_element(node, context);
context.state.analysis.elements.push(node); context.state.analysis.elements.push({ node, path: context.path });
const xmlns = /** @type {AST.Attribute & { value: [AST.Text] } | undefined} */ ( const xmlns = /** @type {AST.Attribute & { value: [AST.Text] } | undefined} */ (
node.attributes.find( node.attributes.find(

@ -9,7 +9,9 @@ import * as e from '../../../errors.js';
* @param {Context} context * @param {Context} context
*/ */
export function Text(node, context) { export function Text(node, context) {
if (node.parent && context.state.parent_element && regex_not_whitespace.test(node.data)) { const in_attribute = context.path.at(-1)?.type === 'Attribute';
if (!in_attribute && context.state.parent_element && regex_not_whitespace.test(node.data)) {
if (!is_tag_valid_with_parent('#text', context.state.parent_element)) { if (!is_tag_valid_with_parent('#text', context.state.parent_element)) {
e.node_invalid_placement(node, 'Text node', context.state.parent_element); e.node_invalid_placement(node, 'Text node', context.state.parent_element);
} }

@ -1,4 +1,4 @@
/** @import { AnalysisState } from '../../types.js' */ /** @import { Context } from '../../types.js' */
/** @import { AST, SvelteNode, TemplateNode } from '#compiler' */ /** @import { AST, SvelteNode, TemplateNode } from '#compiler' */
/** @import { ARIARoleDefinitionKey, ARIARoleRelationConcept, ARIAProperty, ARIAPropertyDefinition, ARIARoleDefinition } from 'aria-query' */ /** @import { ARIARoleDefinitionKey, ARIARoleRelationConcept, ARIAProperty, ARIAPropertyDefinition, ARIARoleDefinition } from 'aria-query' */
import { roles as roles_map, aria, elementRoles } from 'aria-query'; import { roles as roles_map, aria, elementRoles } from 'aria-query';
@ -582,16 +582,17 @@ function get_implicit_role(name, attribute_map) {
const invisible_elements = ['meta', 'html', 'script', 'style']; const invisible_elements = ['meta', 'html', 'script', 'style'];
/** /**
* @param {SvelteNode | null} parent * @param {SvelteNode[]} path
* @param {string[]} elements * @param {string[]} elements
*/ */
function is_parent(parent, elements) { function is_parent(path, elements) {
while (parent) { let i = path.length;
while (i--) {
const parent = path[i];
if (parent.type === 'SvelteElement') return true; // unknown, play it safe, so we don't warn if (parent.type === 'SvelteElement') return true; // unknown, play it safe, so we don't warn
if (parent.type === 'RegularElement') { if (parent.type === 'RegularElement') {
return elements.includes(parent.name); return elements.includes(parent.name);
} }
parent = /** @type {TemplateNode} */ (parent).parent;
} }
return false; return false;
} }
@ -683,9 +684,9 @@ function get_static_text_value(attribute) {
/** /**
* @param {AST.RegularElement | AST.SvelteElement} node * @param {AST.RegularElement | AST.SvelteElement} node
* @param {AnalysisState} state * @param {Context} context
*/ */
export function check_element(node, state) { export function check_element(node, context) {
/** @type {Map<string, AST.Attribute>} */ /** @type {Map<string, AST.Attribute>} */
const attribute_map = new Map(); const attribute_map = new Map();
@ -792,7 +793,7 @@ export function check_element(node, state) {
} }
// Footers and headers are special cases, and should not have redundant roles unless they are the children of sections or articles. // Footers and headers are special cases, and should not have redundant roles unless they are the children of sections or articles.
const is_parent_section_or_article = is_parent(node.parent, ['section', 'article']); const is_parent_section_or_article = is_parent(context.path, ['section', 'article']);
if (!is_parent_section_or_article) { if (!is_parent_section_or_article) {
const has_nested_redundant_role = const has_nested_redundant_role =
current_role === a11y_nested_implicit_semantics.get(node.name); current_role === a11y_nested_implicit_semantics.get(node.name);
@ -1114,7 +1115,7 @@ export function check_element(node, state) {
} }
if (node.name === 'figcaption') { if (node.name === 'figcaption') {
if (!is_parent(node.parent, ['figure'])) { if (!is_parent(context.path, ['figure'])) {
w.a11y_figcaption_parent(node); w.a11y_figcaption_parent(node);
} }
} }

Loading…
Cancel
Save