Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"@googleapis/calendar": "^11.0.1",
"@hackmd/api": "^2.5.0",
"@octokit/rest": "^22.0.0",
"dedent": "^1.6.0"
"dedent": "^1.6.0",
"dotenv": "^17.2.2"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
Expand Down
4 changes: 3 additions & 1 deletion src/meeting.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';

import { parse } from 'dotenv';

import { DEFAULT_CONFIG } from './constants.mjs';
import * as dates from './utils/dates.mjs';
import * as templates from './utils/templates.mjs';
Expand Down Expand Up @@ -32,7 +34,7 @@ export const readMeetingConfig = async config => {
invited,
observers,
baseMeetingInfo,
properties: templates.parseMeetingProperties(baseMeetingInfo),
properties: parse(baseMeetingInfo),
};
};

Expand Down
23 changes: 0 additions & 23 deletions src/utils/templates.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,3 @@ export const parseVariables = (template, variables) => {

return processed;
};

/**
* Simple parser for template properties (KEY="value" format)
* @param {string} content - Template content
* @returns {Record<string, string>} Parsed properties
*/
export const parseMeetingProperties = content => {
const properties = {};

// Handle multiline properties first with a generic regex
// Matches: KEY="multiline content" where content can span multiple lines
const multilineMatches = content.matchAll(
/^([A-Z_][A-Z0-9_]*)="([\s\S]*?)"$/gm
);

for (const match of multilineMatches) {
const [, key, value] = match;

properties[key] = value;
}

return properties;
};
150 changes: 1 addition & 149 deletions test/utils/templates.test.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import assert from 'node:assert';
import { describe, it } from 'node:test';

import {
parseVariables,
parseMeetingProperties,
} from '../../src/utils/templates.mjs';
import { parseVariables } from '../../src/utils/templates.mjs';

describe('Utils - Templates', () => {
describe('parseVariables', () => {
Expand Down Expand Up @@ -118,149 +115,4 @@ Line 3: Hello again`
);
});
});

describe('parseMeetingProperties', () => {
it('should parse simple property', () => {
const content = 'NAME="John Doe"';

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, { NAME: 'John Doe' });
});

it('should parse multiple properties', () => {
const content = `NAME="John Doe"
EMAIL="john@example.com"
ROLE="Developer"`;

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, {
NAME: 'John Doe',
EMAIL: 'john@example.com',
ROLE: 'Developer',
});
});

it('should parse multiline property values', () => {
const content = `DESCRIPTION="This is a
multiline description
with several lines"`;

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, {
DESCRIPTION: 'This is a\nmultiline description\nwith several lines',
});
});

it('should parse properties with underscores and numbers', () => {
const content = `VAR_1="value1"
VAR_2_TEST="value2"
VAR3="value3"`;

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, {
VAR_1: 'value1',
VAR_2_TEST: 'value2',
VAR3: 'value3',
});
});

it('should handle empty property values', () => {
const content = 'EMPTY=""';

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, { EMPTY: '' });
});

it('should handle properties with special characters in values', () => {
const content = 'SPECIAL="Value with $pecial ch@rs & symbols!"';

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, {
SPECIAL: 'Value with $pecial ch@rs & symbols!',
});
});

it('should handle properties with quotes in values', () => {
const content = `QUOTED="He said \\"Hello\\" to me"`;

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, {
QUOTED: 'He said \\"Hello\\" to me',
});
});

it('should handle content with no properties', () => {
const content = 'Just some text without properties';

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, {});
});

it('should handle empty content', () => {
const content = '';

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, {});
});

it('should handle mixed content with properties and other text', () => {
const content = `Some random text
NAME="John Doe"
More text here
EMAIL="john@example.com"
Final text`;

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, {
NAME: 'John Doe',
EMAIL: 'john@example.com',
});
});

it('should handle properties with markdown-like content', () => {
const content = `DESCRIPTION="# Meeting Notes

## Agenda
- Item 1
- Item 2

**Important**: Don't forget!"`;

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, {
DESCRIPTION: `# Meeting Notes

## Agenda
- Item 1
- Item 2

**Important**: Don't forget!`,
});
});

it('should handle properties with URLs and special formatting', () => {
const content = `LINK="https://example.com/path?param=value&other=123"
INSTRUCTIONS="Join at: https://zoom.us/j/123456789
Passcode: 123456"`;

const result = parseMeetingProperties(content);

assert.deepStrictEqual(result, {
LINK: 'https://example.com/path?param=value&other=123',
INSTRUCTIONS: `Join at: https://zoom.us/j/123456789
Passcode: 123456`,
});
});
});
});
Loading