CtrlK
BlogDocsLog inGet started
Tessl Logo

mps-aspect-actions

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.

78

Quality

100%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

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.

Related Skills

  • 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.
Repository
JetBrains/MPS
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.