aeria-populate 0.0.2 → 0.0.4

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 CHANGED
@@ -2,5 +2,33 @@
2
2
 
3
3
  ## Usage
4
4
 
5
- ...
5
+ - `--compileMarkdown/-c`: will compile Markdown to HTML before inserting
6
+ - `--dropCollections/-d`: will drop matching collections before inserting
7
+ - `--watch/-w`: watch mode (can not be used together with `--drop-collections`)
8
+
9
+ ```sh
10
+ # when --env-file is applicable
11
+ node --env-file .env node_modules/aeria-populate/bin/index.js "content/**/*.md"
12
+
13
+ # otherwise
14
+ npx aeria-populate "content/**/*.md"
15
+ npx aeria-populate -c "content/**/*.md"
16
+ ```
17
+
18
+ ## Frontmatter format
19
+
20
+ ```md
21
+ ---
22
+ collection: person
23
+ unique: slug
24
+ content: description
25
+ document:
26
+ slug: john-doe
27
+ sex: male
28
+ ---
29
+
30
+ # John Doe
31
+
32
+ This will be inserted in the `description` property...
33
+ ```
6
34
 
package/dist/cli.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const main: () => Promise<never>;
1
+ export declare const main: () => Promise<void>;
package/dist/cli.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { getDatabase, insert, createContext } from 'aeria';
2
2
  import { parseArgs, styleText, inspect } from 'node:util';
3
+ import * as fs from 'node:fs';
3
4
  import * as yaml from 'yaml';
4
5
  import * as markdown from 'marked';
5
- import * as fs from 'fs';
6
+ import * as chokidar from 'chokidar';
6
7
  const { positionals, values: opts } = parseArgs({
7
8
  allowPositionals: true,
8
9
  options: {
@@ -10,6 +11,14 @@ const { positionals, values: opts } = parseArgs({
10
11
  type: 'boolean',
11
12
  short: 'c',
12
13
  },
14
+ dropCollections: {
15
+ type: 'boolean',
16
+ short: 'd',
17
+ },
18
+ watch: {
19
+ type: 'boolean',
20
+ short: 'w',
21
+ },
13
22
  },
14
23
  });
15
24
  const dbPromise = getDatabase();
@@ -26,11 +35,7 @@ const isValidFrontmatterObject = (value) => {
26
35
  && typeof value.content === 'string'
27
36
  && typeof value.document === 'object');
28
37
  };
29
- const work = async (text) => {
30
- const { db } = await dbPromise;
31
- if (!db) {
32
- throw new Error();
33
- }
38
+ const parseMarkdown = async (text) => {
34
39
  const [, frontmatterString, ...splitContent] = text.split('---');
35
40
  let content = splitContent.join('---').trim();
36
41
  if (opts.compileMarkdown) {
@@ -40,6 +45,17 @@ const work = async (text) => {
40
45
  if (!isValidFrontmatterObject(frontmatter)) {
41
46
  throw new Error('invalid frontmatter');
42
47
  }
48
+ return {
49
+ frontmatter,
50
+ content,
51
+ };
52
+ };
53
+ const work = async (text) => {
54
+ const { db } = await dbPromise;
55
+ if (!db) {
56
+ throw new Error();
57
+ }
58
+ const { frontmatter, content } = await parseMarkdown(text);
43
59
  const context = await createContext({
44
60
  collectionName: frontmatter.collection,
45
61
  });
@@ -74,47 +90,90 @@ const work = async (text) => {
74
90
  existing,
75
91
  };
76
92
  };
93
+ const visitFile = async (file) => {
94
+ let failed = 0, successful = 0;
95
+ const content = await fs.promises.readFile(file, {
96
+ encoding: 'utf-8',
97
+ });
98
+ const { insertion: { error }, frontmatter, existing } = await work(content);
99
+ const uniqueName = styleText(['bold'], frontmatter.document[frontmatter.unique]);
100
+ const collectionName = styleText(['bold'], frontmatter.collection);
101
+ if (error) {
102
+ const actionText = existing
103
+ ? `update ${uniqueName} into collection`
104
+ : `add ${uniqueName} to collection`;
105
+ console.log(styleText(['red'], 'x'), "couldn't", actionText, collectionName);
106
+ console.log(inspect(error, {
107
+ depth: null,
108
+ }));
109
+ failed++;
110
+ }
111
+ else {
112
+ const actionText = existing
113
+ ? 'updated into collection'
114
+ : 'added to collection';
115
+ console.log(styleText(['green'], '✓'), uniqueName, 'successfully', actionText, collectionName);
116
+ successful++;
117
+ }
118
+ return {
119
+ failed,
120
+ successful,
121
+ };
122
+ };
77
123
  export const main = async () => {
78
124
  const [pattern] = positionals;
79
125
  if (!pattern) {
80
126
  console.error('this command takes a glob pattern as positional parameter');
81
127
  process.exit(1);
82
128
  }
83
- const files = fs.promises.glob(pattern);
84
- let failed = 0, sucessful = 0;
85
- for await (const file of files) {
86
- const content = await fs.promises.readFile(file, {
87
- encoding: 'utf-8',
129
+ const { client, db } = await dbPromise;
130
+ if (!db) {
131
+ throw new Error();
132
+ }
133
+ const files = await Array.fromAsync(fs.promises.glob(pattern));
134
+ if (opts.watch) {
135
+ if (opts.dropCollections) {
136
+ console.error("--dropCollections can't be used together with --watch");
137
+ process.exit(1);
138
+ }
139
+ const watcher = chokidar.watch(files);
140
+ console.log('watching for changes in ', styleText(['bold'], pattern));
141
+ watcher.on('change', async (filePath) => {
142
+ await client.connect();
143
+ await visitFile(filePath);
88
144
  });
89
- const { insertion: { error }, frontmatter, existing } = await work(content);
90
- const uniqueName = styleText(['bold'], frontmatter.document[frontmatter.unique]);
91
- const collectionName = styleText(['bold'], frontmatter.collection);
92
- if (error) {
93
- const actionText = existing
94
- ? `update ${uniqueName} into collection`
95
- : `add ${uniqueName} to collection`;
96
- console.log(styleText(['red'], 'x'), "couldn't", actionText, collectionName);
97
- console.log(inspect(error, {
98
- depth: null,
99
- }));
100
- failed++;
145
+ }
146
+ else {
147
+ let failed = 0, successful = 0, dropped = 0;
148
+ const collections = [];
149
+ for (const file of files) {
150
+ const content = await fs.promises.readFile(file, {
151
+ encoding: 'utf-8',
152
+ });
153
+ const { frontmatter } = await parseMarkdown(content);
154
+ collections.push(frontmatter.collection);
155
+ }
156
+ if (opts.dropCollections) {
157
+ for (const collection of collections) {
158
+ if ((await db.listCollections().toArray()).some((subject) => collection === subject.name)) {
159
+ await db.collection(collection).drop();
160
+ console.log(styleText(['green'], '✓'), 'dropped collection', styleText(['bold'], collection));
161
+ dropped++;
162
+ }
163
+ }
164
+ }
165
+ for (const file of files) {
166
+ const result = await visitFile(file);
167
+ failed += result.failed;
168
+ successful += result.successful;
101
169
  }
102
- else {
103
- const actionText = existing
104
- ? 'updated into collection'
105
- : 'added to collection';
106
- console.log(styleText(['green'], '✓'), uniqueName, 'successfully', actionText, collectionName);
107
- sucessful++;
170
+ console.log(dropped, 'dropped collections:', collections.map((collection) => styleText(['bold'], collection)).join(', '));
171
+ console.log(successful, 'documents imported successfully');
172
+ console.log(failed, 'failed to import');
173
+ if (failed) {
174
+ await client.close();
175
+ process.exit(1);
108
176
  }
109
177
  }
110
- console.log(sucessful, 'documents imported sucessfully');
111
- console.log(failed, 'failed to import');
112
- const { client } = await dbPromise;
113
178
  await client.close();
114
- if (failed) {
115
- process.exit(1);
116
- }
117
- else {
118
- process.exit(0);
119
- }
120
179
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aeria-populate",
3
3
  "type": "module",
4
- "version": "0.0.2",
4
+ "version": "0.0.4",
5
5
  "description": "",
6
6
  "license": "ISC",
7
7
  "keywords": [],
@@ -20,9 +20,10 @@
20
20
  "aeria": "file:../aeria"
21
21
  },
22
22
  "peerDependencies": {
23
- "aeria": "^0.0.331"
23
+ "aeria": "^0.0.332"
24
24
  },
25
25
  "dependencies": {
26
+ "chokidar": "^4.0.3",
26
27
  "marked": "^16.0.0",
27
28
  "yaml": "^2.8.0"
28
29
  },