schema tree FEATURE add internal standard module metadata
diff --git a/src/schema_compile.c b/src/schema_compile.c
index 3dcc175..0a44157 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -1139,54 +1139,6 @@
     return LY_SUCCESS;
 }
 
-static LY_ERR
-lys_compile_ietf_netconf_wd_annotation(struct lysc_ctx *ctx, struct lys_module *mod)
-{
-    struct lysc_ext_instance *ext;
-    struct lysp_ext_instance *ext_p = NULL;
-    struct lysp_stmt *stmt;
-    const struct lys_module *ext_mod;
-    LY_ERR ret = LY_SUCCESS;
-
-    /* create the parsed extension instance manually */
-    ext_p = calloc(1, sizeof *ext_p);
-    LY_CHECK_ERR_GOTO(!ext_p, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
-    LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "md:annotation", 0, &ext_p->name), cleanup);
-    LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "default", 0, &ext_p->argument), cleanup);
-    ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
-    ext_p->insubstmt_index = 0;
-
-    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
-    LY_CHECK_ERR_GOTO(!stmt, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
-    LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "type", 0, &stmt->stmt), cleanup);
-    LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "boolean", 0, &stmt->arg), cleanup);
-    stmt->kw = LY_STMT_TYPE;
-
-    /* allocate new extension instance */
-    LY_ARRAY_NEW_GOTO(mod->ctx, mod->compiled->exts, ext, ret, cleanup);
-
-    /* manually get extension definition module */
-    ext_mod = ly_ctx_get_module_latest(ctx->ctx, "ietf-yang-metadata");
-
-    /* compile the extension instance */
-    ret = lys_compile_ext(ctx, ext_p, ext, mod->compiled, LYEXT_PAR_MODULE, ext_mod);
-    if (ret == LY_ENOT) {
-        /* free the extension */
-        lysc_ext_instance_free(ctx->ctx, ext);
-        LY_ARRAY_DECREMENT_FREE(mod->compiled->exts);
-
-        ret = LY_SUCCESS;
-        goto cleanup;
-    } else if (ret) {
-        goto cleanup;
-    }
-
-cleanup:
-    lysp_ext_instance_free(ctx->ctx, ext_p);
-    free(ext_p);
-    return ret;
-}
-
 /**
  * @brief Compile default value(s) for leaf or leaf-list expecting a complete compiled schema tree.
  *
@@ -1726,24 +1678,6 @@
     }
     ctx.pmod = sp;
 
-#if 0
-    /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
-     * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
-     * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
-     * the anotation definitions available in the internal schema structure. */
-    if (ly_strequal(mod->name, "ietf-netconf", 0)) {
-        if (lyp_add_ietf_netconf_annotations(mod)) {
-            lys_free(mod, NULL, 1, 1);
-            return NULL;
-        }
-    }
-#endif
-
-    /* add ietf-netconf-with-defaults "default" metadata to the compiled module */
-    if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
-        LY_CHECK_GOTO(ret = lys_compile_ietf_netconf_wd_annotation(&ctx, mod), error);
-    }
-
     /* there can be no leftover deviations or augments */
     LY_CHECK_ERR_GOTO(ctx.augs.count, LOGINT(ctx.ctx); ret = LY_EINT, error);
     LY_CHECK_ERR_GOTO(ctx.devs.count, LOGINT(ctx.ctx); ret = LY_EINT, error);
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 4ba3827..e933995 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -778,6 +778,187 @@
     return ret;
 }
 
+/**
+ * @brief Add ietf-netconf metadata to the parsed module. Operation, filter, and select are added.
+ *
+ * @param[in] mod Parsed module to add to.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR on error.
+ */
+static LY_ERR
+lys_parsed_add_internal_ietf_netconf(struct lysp_module *mod)
+{
+    struct lysp_ext_instance *ext_p;
+    struct lysp_stmt *stmt;
+    struct lysp_import *imp;
+
+    /*
+     * 1) edit-config's operation
+     */
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
+    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "operation", 0, &ext_p->argument));
+    ext_p->flags = LYS_INTERNAL;
+    ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
+    ext_p->insubstmt_index = 0;
+
+    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
+    stmt->kw = LY_STMT_TYPE;
+
+    stmt->child = calloc(1, sizeof *stmt->child);
+    stmt = stmt->child;
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "merge", 0, &stmt->arg));
+    stmt->kw = LY_STMT_ENUM;
+
+    stmt->next = calloc(1, sizeof *stmt->child);
+    stmt = stmt->next;
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "replace", 0, &stmt->arg));
+    stmt->kw = LY_STMT_ENUM;
+
+    stmt->next = calloc(1, sizeof *stmt->child);
+    stmt = stmt->next;
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "create", 0, &stmt->arg));
+    stmt->kw = LY_STMT_ENUM;
+
+    stmt->next = calloc(1, sizeof *stmt->child);
+    stmt = stmt->next;
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "delete", 0, &stmt->arg));
+    stmt->kw = LY_STMT_ENUM;
+
+    stmt->next = calloc(1, sizeof *stmt->child);
+    stmt = stmt->next;
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "remove", 0, &stmt->arg));
+    stmt->kw = LY_STMT_ENUM;
+
+    /*
+     * 2) filter's type
+     */
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
+    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &ext_p->argument));
+    ext_p->flags = LYS_INTERNAL;
+    ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
+    ext_p->insubstmt_index = 0;
+
+    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
+    stmt->kw = LY_STMT_TYPE;
+
+    stmt->child = calloc(1, sizeof *stmt->child);
+    stmt = stmt->child;
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "subtree", 0, &stmt->arg));
+    stmt->kw = LY_STMT_ENUM;
+
+    stmt->next = calloc(1, sizeof *stmt->child);
+    stmt = stmt->next;
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "xpath", 0, &stmt->arg));
+    stmt->kw = LY_STMT_ENUM;
+
+    /* if-feature for enum allowed only for YANG 1.1 modules */
+    if (mod->version >= LYS_VERSION_1_1) {
+        stmt->child = calloc(1, sizeof *stmt->child);
+        stmt = stmt->child;
+        LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+        LY_CHECK_RET(lydict_insert(mod->mod->ctx, "if-feature", 0, &stmt->stmt));
+        LY_CHECK_RET(lydict_insert(mod->mod->ctx, "xpath", 0, &stmt->arg));
+        stmt->kw = LY_STMT_IF_FEATURE;
+    }
+
+    /*
+     * 3) filter's select
+     */
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
+    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "select", 0, &ext_p->argument));
+    ext_p->flags = LYS_INTERNAL;
+    ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
+    ext_p->insubstmt_index = 0;
+
+    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_:xpath1.0", 0, &stmt->arg));
+    stmt->kw = LY_STMT_TYPE;
+
+    /* create new imports for the used prefixes */
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
+
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
+    imp->flags = LYS_INTERNAL;
+
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
+
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-types", 0, &imp->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_", 0, &imp->prefix));
+    imp->flags = LYS_INTERNAL;
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Add ietf-netconf-with-defaults "default" metadata to the parsed module.
+ *
+ * @param[in] mod Parsed module to add to.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR on error.
+ */
+static LY_ERR
+lys_parsed_add_internal_ietf_netconf_with_defaults(struct lysp_module *mod)
+{
+    struct lysp_ext_instance *ext_p;
+    struct lysp_stmt *stmt;
+    struct lysp_import *imp;
+
+    /* add new extension instance */
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
+
+    /* fill in the extension instance fields */
+    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "default", 0, &ext_p->argument));
+    ext_p->flags = LYS_INTERNAL;
+    ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
+    ext_p->insubstmt_index = 0;
+
+    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
+    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "boolean", 0, &stmt->arg));
+    stmt->kw = LY_STMT_TYPE;
+
+    /* create new import for the used prefix */
+    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
+
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
+    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
+    imp->flags = LYS_INTERNAL;
+
+    return LY_SUCCESS;
+}
+
 LY_ERR
 lys_create_module(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, ly_bool implement,
         LY_ERR (*custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
@@ -911,6 +1092,13 @@
         latest->latest_revision = 0;
     }
 
+    /* add internal data in case specific modules were parsed */
+    if (!strcmp(mod->name, "ietf-netconf")) {
+        LY_CHECK_GOTO(ret = lys_parsed_add_internal_ietf_netconf(mod->parsed), error);
+    } else if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
+        LY_CHECK_GOTO(ret = lys_parsed_add_internal_ietf_netconf_with_defaults(mod->parsed), error);
+    }
+
     /* add into context */
     ret = ly_set_add(&ctx->list, mod, 1, NULL);
     LY_CHECK_GOTO(ret, error);