---
title: "EFA, CFA, CB-SEM, and PLS-SEM syntax generation"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{EFA, CFA, CB-SEM, and PLS-SEM syntax generation}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(surveyframe)
```

In v0.3, `surveyframe` generates syntax for lavaan and seminr workflows. Model
fitting remains in the researcher's analysis script. The generated syntax
should be reviewed, copied into the modelling package, and fitted with
modelling choices appropriate to the study.

```{r load}
demo <- sframe_demo_data()
instr <- demo$instrument
```

## EFA planning syntax

`efa_syntax()` creates a small R code block for estimating an exploratory
factor solution with the optional `psych` package.

```{r efa-syntax}
cat(efa_syntax(
  items = c("dm_1", "dm_2", "dm_3", "sq_1", "sq_2", "sq_3"),
  nfactors = 2,
  extraction = "minres",
  rotation = "oblimin"
))
```

## CFA syntax from scale definitions

The simplest CFA workflow uses scales already defined in the instrument.

```{r cfa}
cat(cfa_lavaan_syntax(instr, ordered = TRUE))
```

`cfa_syntax()` remains available as a backward-compatible wrapper.

```{r cfa-wrapper}
cat(cfa_syntax(instr))
```

## Construct objects

Construct objects record the construct ID, label, measurement mode, and
indicator items.

```{r constructs}
dm <- sf_construct(
  id = "DM",
  label = "Digital marketing",
  items = c("dm_1", "dm_2", "dm_3"),
  mode = "reflective"
)

sq <- sf_construct(
  id = "SQ",
  label = "Service quality",
  items = c("sq_1", "sq_2", "sq_3"),
  mode = "reflective"
)

sat <- sf_construct(
  id = "SAT",
  label = "Satisfaction",
  items = c("sat_1", "sat_2"),
  mode = "reflective"
)
```

Construct modes include `reflective`, `composite`, `formative`, and
`single_item`. Lavaan syntax generation in v0.3 is intended for reflective
measurement models. PLS-SEM syntax can use composite-style constructs.

## CB-SEM lavaan syntax

`sf_model()` stores measurement and structural paths. `sem_lavaan_syntax()`
then generates lavaan syntax without requiring `lavaan` to be installed.

```{r cb-sem}
sem_model <- sf_model(
  id = "tourism_sem",
  label = "Tourism structural model",
  type = "cb_sem",
  constructs = list(dm, sq, sat),
  paths = list(
    sf_path("DM", "SQ", label = "a"),
    sf_path("SQ", "SAT", label = "b"),
    sf_path("DM", "SAT", label = "c_prime")
  ),
  indirect = list(
    sf_indirect("DM", "SQ", "SAT", label = "indirect_DM_SQ_SAT")
  ),
  options = list(estimator = "MLR", missing = "fiml", standardised = TRUE)
)

validate_model(sem_model, instr)

cat(sem_lavaan_syntax(sem_model, instr))
```

## PLS-SEM seminr syntax

For PLS-SEM planning, use composite constructs and `seminr_syntax()`.

```{r pls}
pls_model <- sf_model(
  id = "tourism_pls",
  label = "Tourism PLS model",
  type = "pls_sem",
  constructs = list(
    sf_construct("DM", "Digital marketing", c("dm_1", "dm_2", "dm_3"), mode = "composite"),
    sf_construct("SQ", "Service quality", c("sq_1", "sq_2", "sq_3"), mode = "composite"),
    sf_construct("SAT", "Satisfaction", c("sat_1", "sat_2"), mode = "composite")
  ),
  paths = list(
    sf_path("DM", "SQ"),
    sf_path("SQ", "SAT"),
    sf_path("DM", "SAT")
  ),
  options = list(bootstrap = 5000)
)

cat(seminr_syntax(pls_model))
```

## Model JSON

Store model specifications in `.sframe` files and export them as JSON.

```{r model-json}
model_json(sem_model)
```

## Where syntax goes next

The generated lavaan syntax should be copied into `lavaan::cfa()` or
`lavaan::sem()` after selecting estimators, ordered item handling, missing-data
treatment, and reporting options. The generated seminr syntax should be copied
into an analysis script where `seminr` is installed and the researcher has
chosen bootstrapping settings and construct modes.
