@atscript/db-mongo 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ //#region rolldown:runtime
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+
24
+ //#endregion
25
+ const __atscript_db = __toESM(require("@atscript/db"));
26
+
27
+ //#region packages/db-mongo/src/lib/mongo-filter.ts
28
+ const EMPTY = {};
29
+ const mongoVisitor = {
30
+ comparison(field, op, value) {
31
+ if (op === "$eq") return { [field]: value };
32
+ return { [field]: { [op]: value } };
33
+ },
34
+ and(children) {
35
+ if (children.length === 0) return EMPTY;
36
+ if (children.length === 1) return children[0];
37
+ return { $and: children };
38
+ },
39
+ or(children) {
40
+ if (children.length === 0) return { _impossible: true };
41
+ if (children.length === 1) return children[0];
42
+ return { $or: children };
43
+ },
44
+ not(child) {
45
+ return { $nor: [child] };
46
+ }
47
+ };
48
+ function buildMongoFilter(filter) {
49
+ if (!filter || Object.keys(filter).length === 0) return EMPTY;
50
+ return (0, __atscript_db.walkFilter)(filter, mongoVisitor) ?? EMPTY;
51
+ }
52
+
53
+ //#endregion
54
+ Object.defineProperty(exports, '__toESM', {
55
+ enumerable: true,
56
+ get: function () {
57
+ return __toESM;
58
+ }
59
+ });
60
+ Object.defineProperty(exports, 'buildMongoFilter', {
61
+ enumerable: true,
62
+ get: function () {
63
+ return buildMongoFilter;
64
+ }
65
+ });
@@ -0,0 +1,30 @@
1
+ import { walkFilter } from "@atscript/db";
2
+
3
+ //#region packages/db-mongo/src/lib/mongo-filter.ts
4
+ const EMPTY = {};
5
+ const mongoVisitor = {
6
+ comparison(field, op, value) {
7
+ if (op === "$eq") return { [field]: value };
8
+ return { [field]: { [op]: value } };
9
+ },
10
+ and(children) {
11
+ if (children.length === 0) return EMPTY;
12
+ if (children.length === 1) return children[0];
13
+ return { $and: children };
14
+ },
15
+ or(children) {
16
+ if (children.length === 0) return { _impossible: true };
17
+ if (children.length === 1) return children[0];
18
+ return { $or: children };
19
+ },
20
+ not(child) {
21
+ return { $nor: [child] };
22
+ }
23
+ };
24
+ function buildMongoFilter(filter) {
25
+ if (!filter || Object.keys(filter).length === 0) return EMPTY;
26
+ return walkFilter(filter, mongoVisitor) ?? EMPTY;
27
+ }
28
+
29
+ //#endregion
30
+ export { buildMongoFilter };
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
+ //#region rolldown:runtime
4
+ var __create = Object.create;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
21
+ value: mod,
22
+ enumerable: true
23
+ }) : target, mod));
24
+
25
+ //#endregion
26
+ const __atscript_core = __toESM(require("@atscript/core"));
27
+
28
+ //#region packages/db-mongo/src/plugin/annotations.ts
29
+ const analyzers = [
30
+ "lucene.standard",
31
+ "lucene.simple",
32
+ "lucene.whitespace",
33
+ "lucene.english",
34
+ "lucene.french",
35
+ "lucene.german",
36
+ "lucene.italian",
37
+ "lucene.portuguese",
38
+ "lucene.spanish",
39
+ "lucene.chinese",
40
+ "lucene.hindi",
41
+ "lucene.bengali",
42
+ "lucene.russian",
43
+ "lucene.arabic"
44
+ ];
45
+ const annotations = {
46
+ collection: new __atscript_core.AnnotationSpec({
47
+ description: "Marks an interface as a **MongoDB collection**.\n\n- Use together with `@db.table \"name\"` which provides the collection name.\n- Automatically injects a **non-optional** `_id` field if not explicitly defined.\n- `_id` must be of type **`string`**, **`number`**, or **`mongo.objectId`**.\n\n**Example:**\n```atscript\n@db.table \"users\"\n@db.mongo.collection\nexport interface User {\n _id: mongo.objectId\n email: string.email\n}\n```\n",
48
+ nodeType: ["interface"],
49
+ validate(token, args, doc) {
50
+ const parent = token.parentNode;
51
+ const struc = parent?.getDefinition();
52
+ const errors = [];
53
+ if ((0, __atscript_core.isInterface)(parent) && parent.props.has("_id") && (0, __atscript_core.isStructure)(struc)) {
54
+ const _id = parent.props.get("_id");
55
+ const isOptional = !!_id.token("optional");
56
+ if (isOptional) errors.push({
57
+ message: `[db.mongo] _id can't be optional in Mongo Collection`,
58
+ severity: 1,
59
+ range: _id.token("identifier").range
60
+ });
61
+ const definition = _id.getDefinition();
62
+ if (!definition) return errors;
63
+ let wrongType = false;
64
+ if ((0, __atscript_core.isRef)(definition)) {
65
+ const def = doc.unwindType(definition.id, definition.chain)?.def;
66
+ if ((0, __atscript_core.isPrimitive)(def) && !["string", "number"].includes(def.config.type)) wrongType = true;
67
+ } else wrongType = true;
68
+ if (wrongType) errors.push({
69
+ message: `[db.mongo] _id must be of type string, number or mongo.objectId`,
70
+ severity: 1,
71
+ range: _id.token("identifier").range
72
+ });
73
+ }
74
+ return errors;
75
+ },
76
+ modify(token, args, doc) {
77
+ const parent = token.parentNode;
78
+ const struc = parent?.getDefinition();
79
+ if ((0, __atscript_core.isInterface)(parent) && !parent.props.has("_id") && (0, __atscript_core.isStructure)(struc)) struc.addVirtualProp({
80
+ name: "_id",
81
+ type: "mongo.objectId",
82
+ documentation: "Mongodb Primary Key ObjectId"
83
+ });
84
+ }
85
+ }),
86
+ capped: new __atscript_core.AnnotationSpec({
87
+ description: "Creates a **capped collection** with a fixed maximum size.\n\n- Capped collections have fixed size and maintain insertion order.\n- Ideal for logs, event streams, and cache-like data.\n- Changing the cap size requires dropping and recreating the collection — use `@db.sync.method \"drop\"` to allow this.\n\n**Example:**\n```atscript\n@db.table \"logs\"\n@db.mongo.collection\n@db.mongo.capped 10485760, 10000\n@db.sync.method \"drop\"\nexport interface LogEntry {\n message: string\n timestamp: number\n}\n```\n",
88
+ nodeType: ["interface"],
89
+ multiple: false,
90
+ argument: [{
91
+ optional: false,
92
+ name: "size",
93
+ type: "number",
94
+ description: "Maximum size of the collection in **bytes**."
95
+ }, {
96
+ optional: true,
97
+ name: "max",
98
+ type: "number",
99
+ description: "Maximum number of documents in the collection. If omitted, only the byte size limit applies."
100
+ }]
101
+ }),
102
+ search: {
103
+ dynamic: new __atscript_core.AnnotationSpec({
104
+ description: "Creates a **dynamic MongoDB Search Index** that applies to the entire collection.\n\n- **Indexes all text fields automatically** (no need to specify fields).\n- Supports **language analyzers** for text tokenization.\n- Enables **fuzzy search** (typo tolerance) if needed.\n\n**Example:**\n```atscript\n@db.mongo.search.dynamic \"lucene.english\", 1\nexport interface MongoCollection {}\n```\n",
105
+ nodeType: ["interface"],
106
+ multiple: false,
107
+ argument: [{
108
+ optional: true,
109
+ name: "analyzer",
110
+ type: "string",
111
+ description: "The **text analyzer** for tokenization. Defaults to `\"lucene.standard\"`.\n\n**Available options:** `\"lucene.standard\"`, `\"lucene.english\"`, `\"lucene.spanish\"`, etc.",
112
+ values: analyzers
113
+ }, {
114
+ optional: true,
115
+ name: "fuzzy",
116
+ type: "number",
117
+ description: "Maximum typo tolerance (`0-2`). Defaults to `0` (no fuzzy search).\n\n- `0` → Exact match required.\n- `1` → Allows small typos (e.g., `\"mongo\"` ā‰ˆ `\"mango\"`).\n- `2` → More typo tolerance (e.g., `\"mongodb\"` ā‰ˆ `\"mangodb\"`)."
118
+ }]
119
+ }),
120
+ static: new __atscript_core.AnnotationSpec({
121
+ description: "Defines a **MongoDB Atlas Search Index** for the collection. The props can refer to this index using `@db.mongo.search.text` annotation.\n\n- **Creates a named search index** for full-text search.\n- **Specify analyzers and fuzzy search** behavior at the index level.\n- **Fields must explicitly use `@db.mongo.search.text`** to be included in this search index.\n\n**Example:**\n```atscript\n@db.mongo.search.static \"lucene.english\", 1, \"mySearchIndex\"\nexport interface MongoCollection {}\n```\n",
122
+ nodeType: ["interface"],
123
+ multiple: true,
124
+ argument: [
125
+ {
126
+ optional: true,
127
+ name: "analyzer",
128
+ type: "string",
129
+ description: "The text analyzer for tokenization. Defaults to `\"lucene.standard\"`.\n\n**Available options:** `\"lucene.standard\"`, `\"lucene.english\"`, `\"lucene.spanish\"`, `\"lucene.german\"`, etc.",
130
+ values: analyzers
131
+ },
132
+ {
133
+ optional: true,
134
+ name: "fuzzy",
135
+ type: "number",
136
+ description: "Maximum typo tolerance (`0-2`). **Defaults to `0` (no fuzzy matching).**\n\n- `0` → No typos allowed (exact match required).\n- `1` → Allows small typos (e.g., \"mongo\" ā‰ˆ \"mango\").\n- `2` → More typo tolerance (e.g., \"mongodb\" ā‰ˆ \"mangodb\")."
137
+ },
138
+ {
139
+ optional: true,
140
+ name: "indexName",
141
+ type: "string",
142
+ description: "The name of the search index. Fields must reference this name using `@db.mongo.search.text`. If not set, defaults to `\"DEFAULT\"`."
143
+ }
144
+ ]
145
+ }),
146
+ text: new __atscript_core.AnnotationSpec({
147
+ description: "Marks a field to be **included in a MongoDB Atlas Search Index** defined by `@db.mongo.search.static`.\n\n- **The field has to reference an existing search index name**.\n- If index name is not defined, a new search index with default attributes will be created.\n\n**Example:**\n```atscript\n@db.mongo.search.text \"lucene.english\", \"mySearchIndex\"\nfirstName: string\n```\n",
148
+ nodeType: ["prop"],
149
+ multiple: true,
150
+ argument: [{
151
+ optional: true,
152
+ name: "analyzer",
153
+ type: "string",
154
+ description: "The text analyzer for tokenization. Defaults to `\"lucene.standard\"`.\n\n**Available options:** `\"lucene.standard\"`, `\"lucene.english\"`, `\"lucene.spanish\"`, `\"lucene.german\"`, etc.",
155
+ values: analyzers
156
+ }, {
157
+ optional: true,
158
+ name: "indexName",
159
+ type: "string",
160
+ description: "The **name of the search index** defined in `@db.mongo.search.static`. This links the field to the correct index. If not set, defaults to `\"DEFAULT\"`."
161
+ }]
162
+ })
163
+ }
164
+ };
165
+
166
+ //#endregion
167
+ //#region packages/db-mongo/src/plugin/primitives.ts
168
+ const primitives = { mongo: { extensions: { objectId: {
169
+ type: "string",
170
+ documentation: "Represents a **MongoDB ObjectId**.\n\n- Stored as a **string** but can be converted to an ObjectId at runtime.\n- Useful for handling `_id` fields and queries that require ObjectId conversion.\n- Automatically converts string `_id` values into **MongoDB ObjectId** when needed.\n\n**Example:**\n```atscript\nuserId: mongo.objectId\n```\n",
171
+ annotations: { "expect.pattern": { pattern: "^[a-fA-F0-9]{24}$" } }
172
+ } } } };
173
+
174
+ //#endregion
175
+ //#region packages/db-mongo/src/plugin/index.ts
176
+ const MongoPlugin = () => ({
177
+ name: "mongo",
178
+ config() {
179
+ return {
180
+ primitives,
181
+ annotations: { db: { mongo: annotations } }
182
+ };
183
+ }
184
+ });
185
+
186
+ //#endregion
187
+ exports.MongoPlugin = MongoPlugin
188
+ exports.default = MongoPlugin
@@ -0,0 +1,5 @@
1
+ import { TAtscriptPlugin } from '@atscript/core';
2
+
3
+ declare const MongoPlugin: () => TAtscriptPlugin;
4
+
5
+ export { MongoPlugin, MongoPlugin as default };
@@ -0,0 +1,162 @@
1
+ import { AnnotationSpec, isInterface, isPrimitive, isRef, isStructure } from "@atscript/core";
2
+
3
+ //#region packages/db-mongo/src/plugin/annotations.ts
4
+ const analyzers = [
5
+ "lucene.standard",
6
+ "lucene.simple",
7
+ "lucene.whitespace",
8
+ "lucene.english",
9
+ "lucene.french",
10
+ "lucene.german",
11
+ "lucene.italian",
12
+ "lucene.portuguese",
13
+ "lucene.spanish",
14
+ "lucene.chinese",
15
+ "lucene.hindi",
16
+ "lucene.bengali",
17
+ "lucene.russian",
18
+ "lucene.arabic"
19
+ ];
20
+ const annotations = {
21
+ collection: new AnnotationSpec({
22
+ description: "Marks an interface as a **MongoDB collection**.\n\n- Use together with `@db.table \"name\"` which provides the collection name.\n- Automatically injects a **non-optional** `_id` field if not explicitly defined.\n- `_id` must be of type **`string`**, **`number`**, or **`mongo.objectId`**.\n\n**Example:**\n```atscript\n@db.table \"users\"\n@db.mongo.collection\nexport interface User {\n _id: mongo.objectId\n email: string.email\n}\n```\n",
23
+ nodeType: ["interface"],
24
+ validate(token, args, doc) {
25
+ const parent = token.parentNode;
26
+ const struc = parent?.getDefinition();
27
+ const errors = [];
28
+ if (isInterface(parent) && parent.props.has("_id") && isStructure(struc)) {
29
+ const _id = parent.props.get("_id");
30
+ const isOptional = !!_id.token("optional");
31
+ if (isOptional) errors.push({
32
+ message: `[db.mongo] _id can't be optional in Mongo Collection`,
33
+ severity: 1,
34
+ range: _id.token("identifier").range
35
+ });
36
+ const definition = _id.getDefinition();
37
+ if (!definition) return errors;
38
+ let wrongType = false;
39
+ if (isRef(definition)) {
40
+ const def = doc.unwindType(definition.id, definition.chain)?.def;
41
+ if (isPrimitive(def) && !["string", "number"].includes(def.config.type)) wrongType = true;
42
+ } else wrongType = true;
43
+ if (wrongType) errors.push({
44
+ message: `[db.mongo] _id must be of type string, number or mongo.objectId`,
45
+ severity: 1,
46
+ range: _id.token("identifier").range
47
+ });
48
+ }
49
+ return errors;
50
+ },
51
+ modify(token, args, doc) {
52
+ const parent = token.parentNode;
53
+ const struc = parent?.getDefinition();
54
+ if (isInterface(parent) && !parent.props.has("_id") && isStructure(struc)) struc.addVirtualProp({
55
+ name: "_id",
56
+ type: "mongo.objectId",
57
+ documentation: "Mongodb Primary Key ObjectId"
58
+ });
59
+ }
60
+ }),
61
+ capped: new AnnotationSpec({
62
+ description: "Creates a **capped collection** with a fixed maximum size.\n\n- Capped collections have fixed size and maintain insertion order.\n- Ideal for logs, event streams, and cache-like data.\n- Changing the cap size requires dropping and recreating the collection — use `@db.sync.method \"drop\"` to allow this.\n\n**Example:**\n```atscript\n@db.table \"logs\"\n@db.mongo.collection\n@db.mongo.capped 10485760, 10000\n@db.sync.method \"drop\"\nexport interface LogEntry {\n message: string\n timestamp: number\n}\n```\n",
63
+ nodeType: ["interface"],
64
+ multiple: false,
65
+ argument: [{
66
+ optional: false,
67
+ name: "size",
68
+ type: "number",
69
+ description: "Maximum size of the collection in **bytes**."
70
+ }, {
71
+ optional: true,
72
+ name: "max",
73
+ type: "number",
74
+ description: "Maximum number of documents in the collection. If omitted, only the byte size limit applies."
75
+ }]
76
+ }),
77
+ search: {
78
+ dynamic: new AnnotationSpec({
79
+ description: "Creates a **dynamic MongoDB Search Index** that applies to the entire collection.\n\n- **Indexes all text fields automatically** (no need to specify fields).\n- Supports **language analyzers** for text tokenization.\n- Enables **fuzzy search** (typo tolerance) if needed.\n\n**Example:**\n```atscript\n@db.mongo.search.dynamic \"lucene.english\", 1\nexport interface MongoCollection {}\n```\n",
80
+ nodeType: ["interface"],
81
+ multiple: false,
82
+ argument: [{
83
+ optional: true,
84
+ name: "analyzer",
85
+ type: "string",
86
+ description: "The **text analyzer** for tokenization. Defaults to `\"lucene.standard\"`.\n\n**Available options:** `\"lucene.standard\"`, `\"lucene.english\"`, `\"lucene.spanish\"`, etc.",
87
+ values: analyzers
88
+ }, {
89
+ optional: true,
90
+ name: "fuzzy",
91
+ type: "number",
92
+ description: "Maximum typo tolerance (`0-2`). Defaults to `0` (no fuzzy search).\n\n- `0` → Exact match required.\n- `1` → Allows small typos (e.g., `\"mongo\"` ā‰ˆ `\"mango\"`).\n- `2` → More typo tolerance (e.g., `\"mongodb\"` ā‰ˆ `\"mangodb\"`)."
93
+ }]
94
+ }),
95
+ static: new AnnotationSpec({
96
+ description: "Defines a **MongoDB Atlas Search Index** for the collection. The props can refer to this index using `@db.mongo.search.text` annotation.\n\n- **Creates a named search index** for full-text search.\n- **Specify analyzers and fuzzy search** behavior at the index level.\n- **Fields must explicitly use `@db.mongo.search.text`** to be included in this search index.\n\n**Example:**\n```atscript\n@db.mongo.search.static \"lucene.english\", 1, \"mySearchIndex\"\nexport interface MongoCollection {}\n```\n",
97
+ nodeType: ["interface"],
98
+ multiple: true,
99
+ argument: [
100
+ {
101
+ optional: true,
102
+ name: "analyzer",
103
+ type: "string",
104
+ description: "The text analyzer for tokenization. Defaults to `\"lucene.standard\"`.\n\n**Available options:** `\"lucene.standard\"`, `\"lucene.english\"`, `\"lucene.spanish\"`, `\"lucene.german\"`, etc.",
105
+ values: analyzers
106
+ },
107
+ {
108
+ optional: true,
109
+ name: "fuzzy",
110
+ type: "number",
111
+ description: "Maximum typo tolerance (`0-2`). **Defaults to `0` (no fuzzy matching).**\n\n- `0` → No typos allowed (exact match required).\n- `1` → Allows small typos (e.g., \"mongo\" ā‰ˆ \"mango\").\n- `2` → More typo tolerance (e.g., \"mongodb\" ā‰ˆ \"mangodb\")."
112
+ },
113
+ {
114
+ optional: true,
115
+ name: "indexName",
116
+ type: "string",
117
+ description: "The name of the search index. Fields must reference this name using `@db.mongo.search.text`. If not set, defaults to `\"DEFAULT\"`."
118
+ }
119
+ ]
120
+ }),
121
+ text: new AnnotationSpec({
122
+ description: "Marks a field to be **included in a MongoDB Atlas Search Index** defined by `@db.mongo.search.static`.\n\n- **The field has to reference an existing search index name**.\n- If index name is not defined, a new search index with default attributes will be created.\n\n**Example:**\n```atscript\n@db.mongo.search.text \"lucene.english\", \"mySearchIndex\"\nfirstName: string\n```\n",
123
+ nodeType: ["prop"],
124
+ multiple: true,
125
+ argument: [{
126
+ optional: true,
127
+ name: "analyzer",
128
+ type: "string",
129
+ description: "The text analyzer for tokenization. Defaults to `\"lucene.standard\"`.\n\n**Available options:** `\"lucene.standard\"`, `\"lucene.english\"`, `\"lucene.spanish\"`, `\"lucene.german\"`, etc.",
130
+ values: analyzers
131
+ }, {
132
+ optional: true,
133
+ name: "indexName",
134
+ type: "string",
135
+ description: "The **name of the search index** defined in `@db.mongo.search.static`. This links the field to the correct index. If not set, defaults to `\"DEFAULT\"`."
136
+ }]
137
+ })
138
+ }
139
+ };
140
+
141
+ //#endregion
142
+ //#region packages/db-mongo/src/plugin/primitives.ts
143
+ const primitives = { mongo: { extensions: { objectId: {
144
+ type: "string",
145
+ documentation: "Represents a **MongoDB ObjectId**.\n\n- Stored as a **string** but can be converted to an ObjectId at runtime.\n- Useful for handling `_id` fields and queries that require ObjectId conversion.\n- Automatically converts string `_id` values into **MongoDB ObjectId** when needed.\n\n**Example:**\n```atscript\nuserId: mongo.objectId\n```\n",
146
+ annotations: { "expect.pattern": { pattern: "^[a-fA-F0-9]{24}$" } }
147
+ } } } };
148
+
149
+ //#endregion
150
+ //#region packages/db-mongo/src/plugin/index.ts
151
+ const MongoPlugin = () => ({
152
+ name: "mongo",
153
+ config() {
154
+ return {
155
+ primitives,
156
+ annotations: { db: { mongo: annotations } }
157
+ };
158
+ }
159
+ });
160
+
161
+ //#endregion
162
+ export { MongoPlugin, MongoPlugin as default };
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "@atscript/db-mongo",
3
+ "version": "0.1.38",
4
+ "description": "Mongodb plugin for atscript.",
5
+ "keywords": [
6
+ "atscript",
7
+ "mongodb",
8
+ "plugin"
9
+ ],
10
+ "homepage": "https://github.com/moostjs/atscript/tree/main/packages/db-mongo#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/moostjs/atscript/issues"
13
+ },
14
+ "license": "MIT",
15
+ "author": "Artem Maltsev",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/moostjs/atscript.git",
19
+ "directory": "packages/db-mongo"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "skills",
24
+ "scripts/setup-skills.js"
25
+ ],
26
+ "type": "module",
27
+ "bin": {
28
+ "atscript-db-mongo-skill": "./scripts/setup-skills.js"
29
+ },
30
+ "main": "dist/index.mjs",
31
+ "types": "dist/index.d.ts",
32
+ "typesVersions": {
33
+ "*": {
34
+ "plugin": [
35
+ "dist/plugin.d.ts"
36
+ ],
37
+ "agg": [
38
+ "dist/agg.d.ts"
39
+ ],
40
+ "": [
41
+ "dist/index.d.ts"
42
+ ]
43
+ }
44
+ },
45
+ "exports": {
46
+ ".": {
47
+ "types": "./dist/index.d.ts",
48
+ "import": "./dist/index.mjs",
49
+ "require": "./dist/index.cjs"
50
+ },
51
+ "./plugin": {
52
+ "types": "./dist/plugin.d.ts",
53
+ "import": "./dist/plugin.mjs",
54
+ "require": "./dist/plugin.cjs"
55
+ },
56
+ "./agg": {
57
+ "types": "./dist/agg.d.ts",
58
+ "import": "./dist/agg.mjs",
59
+ "require": "./dist/agg.cjs"
60
+ },
61
+ "./package.json": "./package.json"
62
+ },
63
+ "devDependencies": {
64
+ "vitest": "3.2.4"
65
+ },
66
+ "peerDependencies": {
67
+ "mongodb": "^6.17.0",
68
+ "@atscript/core": "^0.1.38",
69
+ "@atscript/db": "^0.1.38",
70
+ "@atscript/typescript": "^0.1.38"
71
+ },
72
+ "build": [
73
+ {},
74
+ {
75
+ "entries": [
76
+ "src/plugin.ts"
77
+ ],
78
+ "dts": true
79
+ },
80
+ {
81
+ "entries": [
82
+ "src/agg.ts"
83
+ ],
84
+ "dts": true
85
+ }
86
+ ],
87
+ "scripts": {
88
+ "pub": "pnpm publish --access public",
89
+ "test": "vitest",
90
+ "setup-skills": "node ./scripts/setup-skills.js"
91
+ }
92
+ }
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ /* prettier-ignore */
3
+ import fs from 'fs'
4
+ import path from 'path'
5
+ import os from 'os'
6
+ import { fileURLToPath } from 'url'
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
9
+
10
+ const SKILL_NAME = 'atscript-db-mongo'
11
+ const SKILL_SRC = path.join(__dirname, '..', 'skills', SKILL_NAME)
12
+
13
+ if (!fs.existsSync(SKILL_SRC)) {
14
+ console.error(`No skills found at ${SKILL_SRC}`)
15
+ console.error('Add your SKILL.md files to the skills/' + SKILL_NAME + '/ directory first.')
16
+ process.exit(1)
17
+ }
18
+
19
+ const AGENTS = {
20
+ 'Claude Code': { dir: '.claude/skills', global: path.join(os.homedir(), '.claude', 'skills') },
21
+ 'Cursor': { dir: '.cursor/skills', global: path.join(os.homedir(), '.cursor', 'skills') },
22
+ 'Windsurf': { dir: '.windsurf/skills', global: path.join(os.homedir(), '.windsurf', 'skills') },
23
+ 'Codex': { dir: '.codex/skills', global: path.join(os.homedir(), '.codex', 'skills') },
24
+ 'OpenCode': { dir: '.opencode/skills', global: path.join(os.homedir(), '.opencode', 'skills') },
25
+ }
26
+
27
+ const args = process.argv.slice(2)
28
+ const isGlobal = args.includes('--global') || args.includes('-g')
29
+ const isPostinstall = args.includes('--postinstall')
30
+ let installed = 0, skipped = 0
31
+ const installedDirs = []
32
+
33
+ for (const [agentName, cfg] of Object.entries(AGENTS)) {
34
+ const targetBase = isGlobal ? cfg.global : path.join(process.cwd(), cfg.dir)
35
+ const agentRootDir = path.dirname(cfg.global) // Check if the agent has ever been installed globally
36
+
37
+ // In postinstall mode: silently skip agents that aren't set up globally
38
+ if (isPostinstall || isGlobal) {
39
+ if (!fs.existsSync(agentRootDir)) { skipped++; continue }
40
+ }
41
+
42
+ const dest = path.join(targetBase, SKILL_NAME)
43
+ try {
44
+ fs.mkdirSync(dest, { recursive: true })
45
+ fs.cpSync(SKILL_SRC, dest, { recursive: true })
46
+ console.log(`āœ… ${agentName}: installed to ${dest}`)
47
+ installed++
48
+ if (!isGlobal) installedDirs.push(cfg.dir + '/' + SKILL_NAME)
49
+ } catch (err) {
50
+ console.warn(`āš ļø ${agentName}: failed — ${err.message}`)
51
+ }
52
+ }
53
+
54
+ // Add locally-installed skill dirs to .gitignore
55
+ if (!isGlobal && installedDirs.length > 0) {
56
+ const gitignorePath = path.join(process.cwd(), '.gitignore')
57
+ let gitignoreContent = ''
58
+ try { gitignoreContent = fs.readFileSync(gitignorePath, 'utf8') } catch {}
59
+ const linesToAdd = installedDirs.filter(d => !gitignoreContent.includes(d))
60
+ if (linesToAdd.length > 0) {
61
+ const hasHeader = gitignoreContent.includes('# AI agent skills')
62
+ const block = (gitignoreContent && !gitignoreContent.endsWith('\n') ? '\n' : '')
63
+ + (hasHeader ? '' : '\n# AI agent skills (auto-generated by setup-skills)\n')
64
+ + linesToAdd.join('\n') + '\n'
65
+ fs.appendFileSync(gitignorePath, block)
66
+ console.log(`šŸ“ Added ${linesToAdd.length} entries to .gitignore`)
67
+ }
68
+ }
69
+
70
+ if (installed === 0 && isPostinstall) {
71
+ // Silence is fine — no agents present, nothing to do
72
+ } else if (installed === 0 && skipped === Object.keys(AGENTS).length) {
73
+ console.log('No agent directories detected. Try --global or run without it for project-local install.')
74
+ } else if (installed === 0) {
75
+ console.log('Nothing installed. Run without --global to install project-locally.')
76
+ } else {
77
+ console.log(`\n✨ Done! Restart your AI agent to pick up the "${SKILL_NAME}" skill.`)
78
+ }
File without changes
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: atscript-db-mongo
3
+ description: Use this skill when working with @atscript/db-mongo — to define MongoDB collections with @db.table and @db.mongo.collection, create indexes with @db.index.plain/@db.index.unique/@db.mongo.index.text, configure Atlas Search with @db.mongo.search.*, control patch strategies with @db.mongo.patch.strategy, use AsCollection for CRUD operations (insert/replace/update/syncIndexes), validate data with createValidator, or configure MongoPlugin in atscript.config.
4
+ ---
5
+
6
+ # @atscript/db-mongo
7
+
8
+ MongoDB metadata extension for Atscript. Defines annotations for collections, indexes, search, and patch strategies, plus runtime classes (`AsCollection`, `AsMongo`) with built-in validation, filtering, querying, and writing.
9
+
10
+ ## How to use this skill
11
+
12
+ Read the domain file that matches the task. Do not load all files — only what you need.
13
+
14
+ | Domain | File | Load when... |
15
+ |--------|------|-------------|
16
+ | Core setup & plugin config | [core.md](core.md) | Installing the plugin, configuring atscript.config, understanding the plugin architecture |
17
+ | Annotations reference | [annotations.md](annotations.md) | Writing .as files with database and MongoDB annotations, understanding annotation arguments |
18
+ | Collections & CRUD | [collections.md](collections.md) | Using AsCollection/AsMongo for insert, replace, update, query, or sync indexes |
19
+ | Patch strategies | [patches.md](patches.md) | Working with @db.mongo.patch.strategy, array patch operations ($insert/$upsert/$update/$remove/$replace) |
20
+
21
+ ## Quick reference
22
+
23
+ ```atscript
24
+ @db.table 'users'
25
+ @db.mongo.collection
26
+ export interface User {
27
+ @db.index.unique 'email_idx'
28
+ email: string.email
29
+
30
+ @db.mongo.index.text 5
31
+ name: string
32
+
33
+ @db.index.plain 'status_idx'
34
+ isActive: boolean
35
+ }
36
+ ```
37
+
38
+ ```typescript
39
+ import { AsMongo } from '@atscript/db-mongo'
40
+ import { User } from './user.as'
41
+
42
+ const asMongo = new AsMongo('mongodb://localhost:27017/mydb')
43
+ const users = asMongo.getCollection(User)
44
+ await users.insert({ email: 'a@b.com', name: 'Alice', isActive: true })
45
+ ```