JetBrains logo

Skill

mps-aspect-actions

define and edit MPS node factories

Covers Architecture Engineering

Description

Use when defining or editing MPS node factories (the "actions" aspect) — `NodeFactories` roots, per-concept `NodeFactory` setup functions that initialize a freshly created node and optionally copy data from a replaced `sampleNode`, plus the actions aspect's `CopyPasteHandlers` and `PasteWrappers` roots. Reach for this skill when a substitution, side transform, completion replacement, or `add new initialized(...)` should preserve fields from the node it is replacing, or when defaults set in a constructor are not enough.

SKILL.md

MPS Actions Aspect

The actions aspect customizes how new nodes of a concept are constructed by the MPS editor — typically during substitution, side transformations, right-transform/<ctrl-space> replacement, or auto-replace. The framework produces an empty instance of the target concept; the setup function then populates it, often copying fields from the node it is replacing (sampleNode). Lives in <lang>/models/<lang>.actions.mps, language jetbrains.mps.lang.actions. The aspect also hosts copy/paste handlers and paste wrappers (see references/copy-paste-and-paste-wrappers.md).

Critical Directives

  • One NodeFactories root per actions model; add per-concept NodeFactory children to it. Do not create one root per concept.
  • One NodeFactory per applicableConcept. Multiple factories for the same concept are not merged.
  • The setup function runs before newNode is attached to the model. newNode.parent, ancestors, and model-wide queries return null/empty. Use the enclosingNode implicit parameter when you need the would-be parent.
  • sampleNode is typed as node<BaseConcept>. Always narrow with ifInstanceOf (sampleNode is <Concept> original) before accessing fields — direct dereference will NPE or fail to compile.
  • Use SPropertyAccess (ref propertyPropertyDeclaration) for properties; use SLinkAccess (ref linkLinkDeclaration) for both containment and reference child roles.
  • Factories do not fire for quotations <C()>, model.add root(<C()>), model.add new root(C), or pure rendering. If you need factory-initialised nodes in generator code, use new node<C>() with explicit property assignments or route creation through an intention that calls add new initialized.
  • Edit factories through MPS MCP tools (mps_mcp_insert_root_node_from_json, mps_mcp_update_node, optionally mps_mcp_parse_java_and_insert with featureKind: "STATEMENTS" for the body). Do not hand-edit .mps files.
  • After editing, validate with mps_mcp_check_root_node_problems on the NodeFactories root and rebuild the language.

Common-Path Workflow

  1. Ensure an actions model exists (<lang>/models/<lang>.actions.mps; create with mps_mcp_create_model and modelName: "<lang>.actions" — aspect ID actions, case-sensitive, no @ suffix; see aspect-model-stereotypes.md). Used languages: jetbrains.mps.lang.actions, jetbrains.mps.baseLanguage, jetbrains.mps.lang.smodel. Add jetbrains.mps.lang.core as the base. Import the structure model of your language.
  2. Create the NodeFactories root via mps_mcp_insert_root_node_from_json (blueprint in references/json-blueprints.md). Set name.
  3. For each concept that needs custom initialization, add a NodeFactory child via mps_mcp_update_node. Set applicableConcept; attach a NodeSetupFunction with a StatementList body.
  4. Fill the body. Typical pattern: ifInstanceOf (sampleNode is <Concept> original) { newNode.<prop> = original.<prop>; ... }. Cross-type narrowing is allowed — see references/setup-function-bodies.md.
  5. Validate with mps_mcp_check_root_node_problems, rebuild the language, exercise in a sandbox.

Implicit Parameters of NodeSetupFunction

AliasFQNTypeNullableNotes
newNodejetbrains.mps.lang.actions.structure.NodeSetupFunction_NewNodenode<applicableConcept>noThe freshly created empty node. Populate it.
sampleNodejetbrains.mps.lang.actions.structure.NodeSetupFunction_SampleNodenode<BaseConcept>yesNode being replaced, if any. Narrow with ifInstanceOf.
enclosingNodejetbrains.mps.lang.actions.structure.NodeSetupFunction_EnclosingNodenode<BaseConcept>yesProspective parent container; null during root-node creation or programmatic creation outside the editor.
indexjetbrains.mps.lang.actions.structure.NodeSetupFunction_Indexint0-based position in the parent collection, or 0 if not in a collection.
model(plain VariableReference in generated Java)SModelyesThe SModel newNode will be inserted into. Most factories don't use this.

Signature surfaced in the editor: (newNode, sampleNode, enclosingNode, index, model) -> void.

  • mps-aspect-behavior — concept constructors are the place to set defaults that don't depend on the node being replaced. Use a constructor for intrinsic defaults, a NodeFactory for context-sensitive carry-over.
  • mps-aspect-intentions — intentions that call add new initialized(...) route through factories. The NF_* family is documented in the intentions skill's references/factory-initialized.md.
  • mps-aspect-generator — generator output bypasses factories (quotations and add new root do not fire factories). Document where the generator must mimic the factory behavior.
  • mps-model-manipulation — full smodel reference: SLinkAccess vs SPropertyAccess, IfInstanceOfStatement, IfInstanceOfVariable, and the NF_* family.
  • mps-aspect-structure-concepts — when adding the concept that applicableConcept targets.
  • mps-aspect-constraints — for canBe* rules that gate insertion before a factory ever runs.

Reference Index

  • Open references/node-factories-and-triggers.md when you need the validated concept ref for NodeFactories / NodeFactory / NodeSetupFunction, the rule that factories are picked by exact applicableConcept (not by subtype inheritance through a more-general parent factory), and the precise list of triggers that fire / do not fire a factory.
  • Open references/setup-function-bodies.md when writing the function body — copying properties vs. child links (SPropertyAccess vs SLinkAccess), cross-type narrowing in ifInstanceOf, the verbatim ChemMastery (same-type property copy) and Kaja (cross-type child-link copy) examples, and the JSON shape for an AssignmentExpression over SLinkAccess.
  • Open references/json-blueprints.md when inserting the NodeFactories root or a NodeFactory child via MCP — minimal blueprints, the full IfInstanceOfStatement body, and the tip on using mps_mcp_parse_java_and_insert to skip the blueprint.
  • Open references/copy-paste-and-paste-wrappers.md when the language needs custom copy pre-processing, paste post-processing, or paste-time wrapping of nodes — these other roots also live in the actions aspect.
  • Open references/concept-reference.md for the validated FQN/ref table — the jetbrains.mps.lang.actions concepts plus the supporting BaseLanguage and smodel concepts used in setup bodies.
  • Open references/common-failures.md when a freshly created node always has defaults, sampleNode.<prop> does not compile, enclosingNode is unexpectedly null, the factory fires twice, or it does not fire from quotations / generator code.

© 2026 YourAI.tools. Every skill from an identity-verified publisher.

Independent catalog. Not affiliated with, endorsed by, or sponsored by Anthropic or any listed publisher. All trademarks belong to their respective owners.