@atscript/db-mongo 0.1.39 → 0.1.41
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.
- package/README.md +11 -11
- package/dist/agg.cjs +26 -65
- package/dist/{agg.d.ts → agg.d.cts} +5 -12
- package/dist/agg.d.mts +18 -0
- package/dist/agg.mjs +19 -35
- package/dist/index.cjs +374 -313
- package/dist/index.d.cts +344 -0
- package/dist/index.d.mts +344 -0
- package/dist/index.mjs +364 -301
- package/dist/mongo-filter-B5ZINZPF.cjs +40 -0
- package/dist/{mongo-filter-CL69Yhcm.mjs → mongo-filter-CcQO-sEh.mjs} +9 -4
- package/dist/plugin.cjs +37 -47
- package/dist/plugin.d.cts +6 -0
- package/dist/plugin.d.mts +6 -0
- package/dist/plugin.mjs +22 -11
- package/package.json +25 -44
- package/scripts/setup-skills.js +53 -43
- package/skills/atscript-db-mongo/SKILL.md +11 -11
- package/skills/atscript-db-mongo/collections.md +29 -28
- package/skills/atscript-db-mongo/core.md +6 -5
- package/skills/atscript-db-mongo/patches.md +17 -16
- package/LICENSE +0 -21
- package/dist/agg-CUX5Jb_A.mjs +0 -75
- package/dist/agg-FBVtOv9k.cjs +0 -77
- package/dist/index.d.ts +0 -336
- package/dist/mongo-filter-C8w5by9H.cjs +0 -65
- package/dist/plugin.d.ts +0 -5
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
let _atscript_db = require("@atscript/db");
|
|
2
|
+
//#region src/lib/mongo-filter.ts
|
|
3
|
+
const EMPTY = {};
|
|
4
|
+
const mongoVisitor = {
|
|
5
|
+
comparison(field, op, value) {
|
|
6
|
+
if (op === "$eq") return { [field]: value };
|
|
7
|
+
return { [field]: { [op]: value } };
|
|
8
|
+
},
|
|
9
|
+
and(children) {
|
|
10
|
+
if (children.length === 0) return EMPTY;
|
|
11
|
+
if (children.length === 1) return children[0];
|
|
12
|
+
return { $and: children };
|
|
13
|
+
},
|
|
14
|
+
or(children) {
|
|
15
|
+
if (children.length === 0) return { _impossible: true };
|
|
16
|
+
if (children.length === 1) return children[0];
|
|
17
|
+
return { $or: children };
|
|
18
|
+
},
|
|
19
|
+
not(child) {
|
|
20
|
+
return { $nor: [child] };
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Translates a generic {@link FilterExpr} into a MongoDB-compatible
|
|
25
|
+
* {@link Filter} document.
|
|
26
|
+
*
|
|
27
|
+
* MongoDB's query language is nearly identical to the `FilterExpr` structure,
|
|
28
|
+
* so this is largely a structural pass-through via the `walkFilter` visitor.
|
|
29
|
+
*/
|
|
30
|
+
function buildMongoFilter(filter) {
|
|
31
|
+
if (!filter || Object.keys(filter).length === 0) return EMPTY;
|
|
32
|
+
return (0, _atscript_db.walkFilter)(filter, mongoVisitor) ?? EMPTY;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
Object.defineProperty(exports, "buildMongoFilter", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
get: function() {
|
|
38
|
+
return buildMongoFilter;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { walkFilter } from "@atscript/db";
|
|
2
|
-
|
|
3
|
-
//#region packages/db-mongo/src/lib/mongo-filter.ts
|
|
2
|
+
//#region src/lib/mongo-filter.ts
|
|
4
3
|
const EMPTY = {};
|
|
5
4
|
const mongoVisitor = {
|
|
6
5
|
comparison(field, op, value) {
|
|
@@ -21,10 +20,16 @@ const mongoVisitor = {
|
|
|
21
20
|
return { $nor: [child] };
|
|
22
21
|
}
|
|
23
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* Translates a generic {@link FilterExpr} into a MongoDB-compatible
|
|
25
|
+
* {@link Filter} document.
|
|
26
|
+
*
|
|
27
|
+
* MongoDB's query language is nearly identical to the `FilterExpr` structure,
|
|
28
|
+
* so this is largely a structural pass-through via the `walkFilter` visitor.
|
|
29
|
+
*/
|
|
24
30
|
function buildMongoFilter(filter) {
|
|
25
31
|
if (!filter || Object.keys(filter).length === 0) return EMPTY;
|
|
26
32
|
return walkFilter(filter, mongoVisitor) ?? EMPTY;
|
|
27
33
|
}
|
|
28
|
-
|
|
29
34
|
//#endregion
|
|
30
|
-
export { buildMongoFilter };
|
|
35
|
+
export { buildMongoFilter as t };
|
package/dist/plugin.cjs
CHANGED
|
@@ -1,31 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
1
|
+
Object.defineProperties(exports, {
|
|
2
|
+
__esModule: { value: true },
|
|
3
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
+
});
|
|
5
|
+
let _atscript_core = require("@atscript/core");
|
|
6
|
+
//#region src/plugin/annotations.ts
|
|
29
7
|
const analyzers = [
|
|
30
8
|
"lucene.standard",
|
|
31
9
|
"lucene.simple",
|
|
@@ -42,18 +20,33 @@ const analyzers = [
|
|
|
42
20
|
"lucene.russian",
|
|
43
21
|
"lucene.arabic"
|
|
44
22
|
];
|
|
23
|
+
/**
|
|
24
|
+
* MongoDB-specific annotations.
|
|
25
|
+
*
|
|
26
|
+
* Merged into the global config under `{ db: { mongo: ... } }` so they
|
|
27
|
+
* live alongside core's `@db.table`, `@db.index.*`, etc.
|
|
28
|
+
*
|
|
29
|
+
* Annotations removed (now in core):
|
|
30
|
+
* - `@mongo.index.plain` → use `@db.index.plain`
|
|
31
|
+
* - `@mongo.index.unique` → use `@db.index.unique`
|
|
32
|
+
* - `@db.mongo.index.text` → use `@db.index.fulltext` (with optional weight arg)
|
|
33
|
+
* - `@db.mongo.patch.strategy` → use `@db.patch.strategy`
|
|
34
|
+
* - `@db.mongo.array.uniqueItems` → use `@expect.array.uniqueItems`
|
|
35
|
+
* - `@db.mongo.autoIndexes` → removed (use explicit syncIndexes() calls)
|
|
36
|
+
* - `@db.mongo.search.vector` → use `@db.search.vector` (generic, in @atscript/db/plugin)
|
|
37
|
+
* - `@db.mongo.search.filter` → use `@db.search.filter` (generic, in @atscript/db/plugin)
|
|
38
|
+
*/
|
|
45
39
|
const annotations = {
|
|
46
|
-
collection: new
|
|
40
|
+
collection: new _atscript_core.AnnotationSpec({
|
|
47
41
|
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
42
|
nodeType: ["interface"],
|
|
49
43
|
validate(token, args, doc) {
|
|
50
44
|
const parent = token.parentNode;
|
|
51
45
|
const struc = parent?.getDefinition();
|
|
52
46
|
const errors = [];
|
|
53
|
-
if ((0,
|
|
47
|
+
if ((0, _atscript_core.isInterface)(parent) && parent.props.has("_id") && (0, _atscript_core.isStructure)(struc)) {
|
|
54
48
|
const _id = parent.props.get("_id");
|
|
55
|
-
|
|
56
|
-
if (isOptional) errors.push({
|
|
49
|
+
if (!!_id.token("optional")) errors.push({
|
|
57
50
|
message: `[db.mongo] _id can't be optional in Mongo Collection`,
|
|
58
51
|
severity: 1,
|
|
59
52
|
range: _id.token("identifier").range
|
|
@@ -61,9 +54,9 @@ const annotations = {
|
|
|
61
54
|
const definition = _id.getDefinition();
|
|
62
55
|
if (!definition) return errors;
|
|
63
56
|
let wrongType = false;
|
|
64
|
-
if ((0,
|
|
57
|
+
if ((0, _atscript_core.isRef)(definition)) {
|
|
65
58
|
const def = doc.unwindType(definition.id, definition.chain)?.def;
|
|
66
|
-
if ((0,
|
|
59
|
+
if ((0, _atscript_core.isPrimitive)(def) && !["string", "number"].includes(def.config.type)) wrongType = true;
|
|
67
60
|
} else wrongType = true;
|
|
68
61
|
if (wrongType) errors.push({
|
|
69
62
|
message: `[db.mongo] _id must be of type string, number or mongo.objectId`,
|
|
@@ -73,17 +66,17 @@ const annotations = {
|
|
|
73
66
|
}
|
|
74
67
|
return errors;
|
|
75
68
|
},
|
|
76
|
-
modify(token,
|
|
69
|
+
modify(token, _args, _doc) {
|
|
77
70
|
const parent = token.parentNode;
|
|
78
71
|
const struc = parent?.getDefinition();
|
|
79
|
-
if ((0,
|
|
72
|
+
if ((0, _atscript_core.isInterface)(parent) && !parent.props.has("_id") && (0, _atscript_core.isStructure)(struc)) struc.addVirtualProp({
|
|
80
73
|
name: "_id",
|
|
81
74
|
type: "mongo.objectId",
|
|
82
75
|
documentation: "Mongodb Primary Key ObjectId"
|
|
83
76
|
});
|
|
84
77
|
}
|
|
85
78
|
}),
|
|
86
|
-
capped: new
|
|
79
|
+
capped: new _atscript_core.AnnotationSpec({
|
|
87
80
|
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
81
|
nodeType: ["interface"],
|
|
89
82
|
multiple: false,
|
|
@@ -100,7 +93,7 @@ const annotations = {
|
|
|
100
93
|
}]
|
|
101
94
|
}),
|
|
102
95
|
search: {
|
|
103
|
-
dynamic: new
|
|
96
|
+
dynamic: new _atscript_core.AnnotationSpec({
|
|
104
97
|
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
98
|
nodeType: ["interface"],
|
|
106
99
|
multiple: false,
|
|
@@ -117,7 +110,7 @@ const annotations = {
|
|
|
117
110
|
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
111
|
}]
|
|
119
112
|
}),
|
|
120
|
-
static: new
|
|
113
|
+
static: new _atscript_core.AnnotationSpec({
|
|
121
114
|
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
115
|
nodeType: ["interface"],
|
|
123
116
|
multiple: true,
|
|
@@ -143,7 +136,7 @@ const annotations = {
|
|
|
143
136
|
}
|
|
144
137
|
]
|
|
145
138
|
}),
|
|
146
|
-
text: new
|
|
139
|
+
text: new _atscript_core.AnnotationSpec({
|
|
147
140
|
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
141
|
nodeType: ["prop"],
|
|
149
142
|
multiple: true,
|
|
@@ -162,17 +155,15 @@ const annotations = {
|
|
|
162
155
|
})
|
|
163
156
|
}
|
|
164
157
|
};
|
|
165
|
-
|
|
166
158
|
//#endregion
|
|
167
|
-
//#region
|
|
159
|
+
//#region src/plugin/primitives.ts
|
|
168
160
|
const primitives = { mongo: { extensions: { objectId: {
|
|
169
161
|
type: "string",
|
|
170
162
|
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
163
|
annotations: { "expect.pattern": { pattern: "^[a-fA-F0-9]{24}$" } }
|
|
172
164
|
} } } };
|
|
173
|
-
|
|
174
165
|
//#endregion
|
|
175
|
-
//#region
|
|
166
|
+
//#region src/plugin/index.ts
|
|
176
167
|
const MongoPlugin = () => ({
|
|
177
168
|
name: "mongo",
|
|
178
169
|
config() {
|
|
@@ -182,7 +173,6 @@ const MongoPlugin = () => ({
|
|
|
182
173
|
};
|
|
183
174
|
}
|
|
184
175
|
});
|
|
185
|
-
|
|
186
176
|
//#endregion
|
|
187
|
-
exports.MongoPlugin = MongoPlugin
|
|
188
|
-
exports.default = MongoPlugin
|
|
177
|
+
exports.MongoPlugin = MongoPlugin;
|
|
178
|
+
exports.default = MongoPlugin;
|
package/dist/plugin.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AnnotationSpec, isInterface, isPrimitive, isRef, isStructure } from "@atscript/core";
|
|
2
|
-
|
|
3
|
-
//#region packages/db-mongo/src/plugin/annotations.ts
|
|
2
|
+
//#region src/plugin/annotations.ts
|
|
4
3
|
const analyzers = [
|
|
5
4
|
"lucene.standard",
|
|
6
5
|
"lucene.simple",
|
|
@@ -17,6 +16,22 @@ const analyzers = [
|
|
|
17
16
|
"lucene.russian",
|
|
18
17
|
"lucene.arabic"
|
|
19
18
|
];
|
|
19
|
+
/**
|
|
20
|
+
* MongoDB-specific annotations.
|
|
21
|
+
*
|
|
22
|
+
* Merged into the global config under `{ db: { mongo: ... } }` so they
|
|
23
|
+
* live alongside core's `@db.table`, `@db.index.*`, etc.
|
|
24
|
+
*
|
|
25
|
+
* Annotations removed (now in core):
|
|
26
|
+
* - `@mongo.index.plain` → use `@db.index.plain`
|
|
27
|
+
* - `@mongo.index.unique` → use `@db.index.unique`
|
|
28
|
+
* - `@db.mongo.index.text` → use `@db.index.fulltext` (with optional weight arg)
|
|
29
|
+
* - `@db.mongo.patch.strategy` → use `@db.patch.strategy`
|
|
30
|
+
* - `@db.mongo.array.uniqueItems` → use `@expect.array.uniqueItems`
|
|
31
|
+
* - `@db.mongo.autoIndexes` → removed (use explicit syncIndexes() calls)
|
|
32
|
+
* - `@db.mongo.search.vector` → use `@db.search.vector` (generic, in @atscript/db/plugin)
|
|
33
|
+
* - `@db.mongo.search.filter` → use `@db.search.filter` (generic, in @atscript/db/plugin)
|
|
34
|
+
*/
|
|
20
35
|
const annotations = {
|
|
21
36
|
collection: new AnnotationSpec({
|
|
22
37
|
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",
|
|
@@ -27,8 +42,7 @@ const annotations = {
|
|
|
27
42
|
const errors = [];
|
|
28
43
|
if (isInterface(parent) && parent.props.has("_id") && isStructure(struc)) {
|
|
29
44
|
const _id = parent.props.get("_id");
|
|
30
|
-
|
|
31
|
-
if (isOptional) errors.push({
|
|
45
|
+
if (!!_id.token("optional")) errors.push({
|
|
32
46
|
message: `[db.mongo] _id can't be optional in Mongo Collection`,
|
|
33
47
|
severity: 1,
|
|
34
48
|
range: _id.token("identifier").range
|
|
@@ -48,7 +62,7 @@ const annotations = {
|
|
|
48
62
|
}
|
|
49
63
|
return errors;
|
|
50
64
|
},
|
|
51
|
-
modify(token,
|
|
65
|
+
modify(token, _args, _doc) {
|
|
52
66
|
const parent = token.parentNode;
|
|
53
67
|
const struc = parent?.getDefinition();
|
|
54
68
|
if (isInterface(parent) && !parent.props.has("_id") && isStructure(struc)) struc.addVirtualProp({
|
|
@@ -137,17 +151,15 @@ const annotations = {
|
|
|
137
151
|
})
|
|
138
152
|
}
|
|
139
153
|
};
|
|
140
|
-
|
|
141
154
|
//#endregion
|
|
142
|
-
//#region
|
|
155
|
+
//#region src/plugin/primitives.ts
|
|
143
156
|
const primitives = { mongo: { extensions: { objectId: {
|
|
144
157
|
type: "string",
|
|
145
158
|
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
159
|
annotations: { "expect.pattern": { pattern: "^[a-fA-F0-9]{24}$" } }
|
|
147
160
|
} } } };
|
|
148
|
-
|
|
149
161
|
//#endregion
|
|
150
|
-
//#region
|
|
162
|
+
//#region src/plugin/index.ts
|
|
151
163
|
const MongoPlugin = () => ({
|
|
152
164
|
name: "mongo",
|
|
153
165
|
config() {
|
|
@@ -157,6 +169,5 @@ const MongoPlugin = () => ({
|
|
|
157
169
|
};
|
|
158
170
|
}
|
|
159
171
|
});
|
|
160
|
-
|
|
161
172
|
//#endregion
|
|
162
|
-
export { MongoPlugin, MongoPlugin as default };
|
|
173
|
+
export { MongoPlugin, MongoPlugin as default };
|
package/package.json
CHANGED
|
@@ -1,92 +1,73 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db-mongo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
4
4
|
"description": "Mongodb plugin for atscript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atscript",
|
|
7
7
|
"mongodb",
|
|
8
8
|
"plugin"
|
|
9
9
|
],
|
|
10
|
-
"homepage": "https://github.com/moostjs/atscript/tree/main/packages/db-mongo#readme",
|
|
10
|
+
"homepage": "https://github.com/moostjs/atscript-db/tree/main/packages/db-mongo#readme",
|
|
11
11
|
"bugs": {
|
|
12
|
-
"url": "https://github.com/moostjs/atscript/issues"
|
|
12
|
+
"url": "https://github.com/moostjs/atscript-db/issues"
|
|
13
13
|
},
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"author": "Artem Maltsev",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/moostjs/atscript.git",
|
|
18
|
+
"url": "git+https://github.com/moostjs/atscript-db.git",
|
|
19
19
|
"directory": "packages/db-mongo"
|
|
20
20
|
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"atscript-db-mongo-skill": "./scripts/setup-skills.js"
|
|
23
|
+
},
|
|
21
24
|
"files": [
|
|
22
25
|
"dist",
|
|
23
26
|
"skills",
|
|
24
27
|
"scripts/setup-skills.js"
|
|
25
28
|
],
|
|
26
29
|
"type": "module",
|
|
27
|
-
"bin": {
|
|
28
|
-
"atscript-db-mongo-skill": "./scripts/setup-skills.js"
|
|
29
|
-
},
|
|
30
30
|
"main": "dist/index.mjs",
|
|
31
|
-
"types": "dist/index.d.
|
|
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
|
-
},
|
|
31
|
+
"types": "dist/index.d.mts",
|
|
45
32
|
"exports": {
|
|
46
33
|
".": {
|
|
47
|
-
"types": "./dist/index.d.
|
|
34
|
+
"types": "./dist/index.d.mts",
|
|
48
35
|
"import": "./dist/index.mjs",
|
|
49
36
|
"require": "./dist/index.cjs"
|
|
50
37
|
},
|
|
51
38
|
"./plugin": {
|
|
52
|
-
"types": "./dist/plugin.d.
|
|
39
|
+
"types": "./dist/plugin.d.mts",
|
|
53
40
|
"import": "./dist/plugin.mjs",
|
|
54
41
|
"require": "./dist/plugin.cjs"
|
|
55
42
|
},
|
|
56
43
|
"./agg": {
|
|
57
|
-
"types": "./dist/agg.d.
|
|
44
|
+
"types": "./dist/agg.d.mts",
|
|
58
45
|
"import": "./dist/agg.mjs",
|
|
59
46
|
"require": "./dist/agg.cjs"
|
|
60
47
|
},
|
|
61
48
|
"./package.json": "./package.json"
|
|
62
49
|
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
},
|
|
63
53
|
"devDependencies": {
|
|
64
|
-
"
|
|
54
|
+
"@atscript/core": "^0.1.39",
|
|
55
|
+
"@atscript/typescript": "^0.1.39",
|
|
56
|
+
"mongodb": "^6.17.0",
|
|
57
|
+
"unplugin-atscript": "^0.1.39"
|
|
65
58
|
},
|
|
66
59
|
"peerDependencies": {
|
|
67
|
-
"mongodb": "^6.17.0",
|
|
68
60
|
"@atscript/core": "^0.1.39",
|
|
69
61
|
"@atscript/typescript": "^0.1.39",
|
|
70
|
-
"
|
|
62
|
+
"mongodb": "^6.17.0",
|
|
63
|
+
"@atscript/db": "^0.1.41"
|
|
71
64
|
},
|
|
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
65
|
"scripts": {
|
|
88
|
-
"
|
|
89
|
-
"
|
|
66
|
+
"postinstall": "asc -f dts",
|
|
67
|
+
"build": "vp pack",
|
|
68
|
+
"dev": "vp pack --watch",
|
|
69
|
+
"test": "vp test",
|
|
70
|
+
"check": "vp check",
|
|
90
71
|
"setup-skills": "node ./scripts/setup-skills.js"
|
|
91
72
|
}
|
|
92
73
|
}
|
package/scripts/setup-skills.js
CHANGED
|
@@ -1,78 +1,88 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/* prettier-ignore */
|
|
3
3
|
import fs from 'fs'
|
|
4
|
-
import path from
|
|
5
|
-
import os from
|
|
6
|
-
import { fileURLToPath } from
|
|
4
|
+
import path from "path";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
8
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
|
|
10
|
-
const SKILL_NAME =
|
|
11
|
-
const SKILL_SRC = path.join(__dirname,
|
|
10
|
+
const SKILL_NAME = "atscript-db-mongo";
|
|
11
|
+
const SKILL_SRC = path.join(__dirname, "..", "skills", SKILL_NAME);
|
|
12
12
|
|
|
13
13
|
if (!fs.existsSync(SKILL_SRC)) {
|
|
14
|
-
console.error(`No skills found at ${SKILL_SRC}`)
|
|
15
|
-
console.error(
|
|
16
|
-
process.exit(1)
|
|
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
17
|
}
|
|
18
18
|
|
|
19
19
|
const AGENTS = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
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
26
|
|
|
27
|
-
const args = process.argv.slice(2)
|
|
28
|
-
const isGlobal = args.
|
|
29
|
-
const isPostinstall = args.
|
|
30
|
-
let installed = 0,
|
|
31
|
-
|
|
27
|
+
const args = new Set(process.argv.slice(2));
|
|
28
|
+
const isGlobal = args.has("--global") || args.has("-g");
|
|
29
|
+
const isPostinstall = args.has("--postinstall");
|
|
30
|
+
let installed = 0,
|
|
31
|
+
skipped = 0;
|
|
32
|
+
const installedDirs = [];
|
|
32
33
|
|
|
33
34
|
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
|
|
35
|
+
const targetBase = isGlobal ? cfg.global : path.join(process.cwd(), cfg.dir);
|
|
36
|
+
const agentRootDir = path.dirname(cfg.global); // Check if the agent has ever been installed globally
|
|
36
37
|
|
|
37
38
|
// In postinstall mode: silently skip agents that aren't set up globally
|
|
38
39
|
if (isPostinstall || isGlobal) {
|
|
39
|
-
if (!fs.existsSync(agentRootDir)) {
|
|
40
|
+
if (!fs.existsSync(agentRootDir)) {
|
|
41
|
+
skipped++;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
const dest = path.join(targetBase, SKILL_NAME)
|
|
46
|
+
const dest = path.join(targetBase, SKILL_NAME);
|
|
43
47
|
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 +
|
|
48
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
49
|
+
fs.cpSync(SKILL_SRC, dest, { recursive: true });
|
|
50
|
+
console.log(`✅ ${agentName}: installed to ${dest}`);
|
|
51
|
+
installed++;
|
|
52
|
+
if (!isGlobal) installedDirs.push(cfg.dir + "/" + SKILL_NAME);
|
|
49
53
|
} catch (err) {
|
|
50
|
-
console.warn(`⚠️ ${agentName}: failed — ${err.message}`)
|
|
54
|
+
console.warn(`⚠️ ${agentName}: failed — ${err.message}`);
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
// Add locally-installed skill dirs to .gitignore
|
|
55
59
|
if (!isGlobal && installedDirs.length > 0) {
|
|
56
|
-
const gitignorePath = path.join(process.cwd(),
|
|
57
|
-
let gitignoreContent =
|
|
58
|
-
try {
|
|
59
|
-
|
|
60
|
+
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
61
|
+
let gitignoreContent = "";
|
|
62
|
+
try {
|
|
63
|
+
gitignoreContent = fs.readFileSync(gitignorePath, "utf8");
|
|
64
|
+
} catch {}
|
|
65
|
+
const linesToAdd = installedDirs.filter((d) => !gitignoreContent.includes(d));
|
|
60
66
|
if (linesToAdd.length > 0) {
|
|
61
|
-
const hasHeader = gitignoreContent.includes(
|
|
62
|
-
const block =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
const hasHeader = gitignoreContent.includes("# AI agent skills");
|
|
68
|
+
const block =
|
|
69
|
+
(gitignoreContent && !gitignoreContent.endsWith("\n") ? "\n" : "") +
|
|
70
|
+
(hasHeader ? "" : "\n# AI agent skills (auto-generated by setup-skills)\n") +
|
|
71
|
+
linesToAdd.join("\n") +
|
|
72
|
+
"\n";
|
|
73
|
+
fs.appendFileSync(gitignorePath, block);
|
|
74
|
+
console.log(`📝 Added ${linesToAdd.length} entries to .gitignore`);
|
|
67
75
|
}
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
if (installed === 0 && isPostinstall) {
|
|
71
79
|
// Silence is fine — no agents present, nothing to do
|
|
72
80
|
} else if (installed === 0 && skipped === Object.keys(AGENTS).length) {
|
|
73
|
-
console.log(
|
|
81
|
+
console.log(
|
|
82
|
+
"No agent directories detected. Try --global or run without it for project-local install.",
|
|
83
|
+
);
|
|
74
84
|
} else if (installed === 0) {
|
|
75
|
-
console.log(
|
|
85
|
+
console.log("Nothing installed. Run without --global to install project-locally.");
|
|
76
86
|
} else {
|
|
77
|
-
console.log(`\n✨ Done! Restart your AI agent to pick up the "${SKILL_NAME}" skill.`)
|
|
87
|
+
console.log(`\n✨ Done! Restart your AI agent to pick up the "${SKILL_NAME}" skill.`);
|
|
78
88
|
}
|
|
@@ -11,12 +11,12 @@ MongoDB metadata extension for Atscript. Defines annotations for collections, in
|
|
|
11
11
|
|
|
12
12
|
Read the domain file that matches the task. Do not load all files — only what you need.
|
|
13
13
|
|
|
14
|
-
| Domain
|
|
15
|
-
|
|
16
|
-
| Core setup & plugin config | [core.md](core.md)
|
|
17
|
-
| Annotations reference
|
|
18
|
-
| Collections & CRUD
|
|
19
|
-
| Patch strategies
|
|
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
20
|
|
|
21
21
|
## Quick reference
|
|
22
22
|
|
|
@@ -36,10 +36,10 @@ export interface User {
|
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
```typescript
|
|
39
|
-
import { AsMongo } from
|
|
40
|
-
import { User } from
|
|
39
|
+
import { AsMongo } from "@atscript/db-mongo";
|
|
40
|
+
import { User } from "./user.as";
|
|
41
41
|
|
|
42
|
-
const asMongo = new AsMongo(
|
|
43
|
-
const users = asMongo.getCollection(User)
|
|
44
|
-
await users.insert({ email:
|
|
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
45
|
```
|