skewer-format 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Meta Platforms, Inc. and affiliates.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # Skewer
2
+
3
+ This repo is a idea to build a quiz tool fro exams based on text files alone. All questions and answers are stored in text files, and the tool will read these files to generate quizzes.
4
+
5
+ # Format
6
+
7
+ The format is based on AikenFormat, which is a simple format for multiple-choice questions. But I'm taking that as inspiration and creating my own format that is more flexible and can support different types of questions. Naming it as SkewerFormat.
8
+ The reason for using text instead of JSON and other format is that text is more human-readable and easier to edit. The prime motive is to create all set of questions related to a exam or topic in a single vault of obsidian and just zip and pass.
9
+
10
+ ## Supported Question Types
11
+
12
+ - Multiple Choice
13
+ - True/False
14
+ - Multiple Select
15
+ - Type in the Answer
16
+ - Question Set (a set of questions that are related to each other)
@@ -0,0 +1,2 @@
1
+ export { lexer } from "./src/lexer";
2
+ export { parser } from "./src/parser";
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parser = exports.lexer = void 0;
4
+ var lexer_1 = require("./src/lexer");
5
+ Object.defineProperty(exports, "lexer", { enumerable: true, get: function () { return lexer_1.lexer; } });
6
+ var parser_1 = require("./src/parser");
7
+ Object.defineProperty(exports, "parser", { enumerable: true, get: function () { return parser_1.parser; } });
@@ -0,0 +1,23 @@
1
+ export type Token = {
2
+ type: "KEY";
3
+ value: string;
4
+ } | {
5
+ type: "COLON";
6
+ value: ":";
7
+ } | {
8
+ type: "VALUE";
9
+ value: string;
10
+ } | {
11
+ type: "OPTION_KEY";
12
+ value: string;
13
+ } | {
14
+ type: "DOT";
15
+ value: ".";
16
+ } | {
17
+ type: "OPTION_VALUE";
18
+ value: string;
19
+ } | {
20
+ type: "SENTINEL";
21
+ value: string;
22
+ };
23
+ export declare function lexer(input: string): Token[];
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lexer = lexer;
4
+ function lexer(input) {
5
+ const tokens = [];
6
+ const lines = input
7
+ .split("\n")
8
+ .map(line => line.trim())
9
+ .filter(Boolean);
10
+ for (const line of lines) {
11
+ const optionMatch = line.match(/^([A-Z])\.\s*(.+)$/);
12
+ if (optionMatch) {
13
+ tokens.push({
14
+ type: "OPTION_KEY",
15
+ value: optionMatch[1]
16
+ });
17
+ tokens.push({
18
+ type: "DOT",
19
+ value: "."
20
+ });
21
+ tokens.push({
22
+ type: "OPTION_VALUE",
23
+ value: optionMatch[2]
24
+ });
25
+ continue;
26
+ }
27
+ const keyValueMatch = line.match(/^([A-Z_]+):\s*(.+)$/);
28
+ if (keyValueMatch) {
29
+ tokens.push({
30
+ type: "KEY",
31
+ value: keyValueMatch[1]
32
+ });
33
+ tokens.push({
34
+ type: "COLON",
35
+ value: ":"
36
+ });
37
+ tokens.push({
38
+ type: "VALUE",
39
+ value: keyValueMatch[2]
40
+ });
41
+ }
42
+ const sentinalMatch = line.match(/^---$/m);
43
+ if (sentinalMatch) {
44
+ tokens.push({
45
+ type: "SENTINEL",
46
+ value: "---"
47
+ });
48
+ continue;
49
+ }
50
+ }
51
+ return tokens;
52
+ }
53
+ const input = `
54
+
55
+ ---
56
+ QUESTION: Which of the following best describes the primary purpose of a preloader in web design?
57
+ A. To enhance the visual aesthetics of the website
58
+ B. To ensure faster actual loading times of the website
59
+ C. To create the perception of faster loading times through engaging animations or progress indicators
60
+ D. To provide additional information about the website's content
61
+ ANSWER: C
62
+ EXPLANATION: Preloaders are used to create the perception of faster loading times, engaging users with animations or progress indicators while the website content loads in the background.
63
+
64
+ ---
65
+ QUESTION: In the context of web design, what does SVG stand for and what is its primary use?
66
+ A. Scalable Vector Graphics, used for defining three-dimensional graphics
67
+ B. Simple Vector Graphics, used for creating basic two-dimensional images
68
+ C. Scalable Vector Graphics, used for defining two-dimensional graphics with interactivity and animation support
69
+ D. Standard Vector Graphics, used for standardizing image formats across different platforms
70
+ ANSWER: C
71
+ EXPLANATION: SVG stands for Scalable Vector Graphics, an XML-based vector image format for two-dimensional graphics with support for interactivity and animation.
72
+
73
+ ---
74
+ `;
@@ -0,0 +1,20 @@
1
+ import type { Token } from "./lexer.js";
2
+ interface Question {
3
+ id?: string;
4
+ type?: string;
5
+ question?: string;
6
+ options?: {
7
+ key: string;
8
+ value: string;
9
+ }[];
10
+ answer?: string | Array<string>;
11
+ explanation?: string;
12
+ }
13
+ interface QuestionSet {
14
+ id: string;
15
+ type: string;
16
+ para: string;
17
+ questions: Array<Question>;
18
+ }
19
+ export declare function parser(tokens: Token[]): Array<Question | QuestionSet>;
20
+ export {};
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parser = parser;
4
+ const lexer_js_1 = require("./lexer.js");
5
+ function parser(tokens) {
6
+ var _a;
7
+ const resultArr = [];
8
+ let question = {
9
+ options: []
10
+ };
11
+ let sentinel = "close";
12
+ let currentType;
13
+ let i = 0;
14
+ function resetQuestion() {
15
+ question = {
16
+ options: []
17
+ };
18
+ }
19
+ while (i < tokens.length) {
20
+ const token = tokens[i];
21
+ if (token.type === "SENTINEL") {
22
+ sentinel = "close";
23
+ resultArr.push(question);
24
+ resetQuestion();
25
+ i++;
26
+ continue;
27
+ }
28
+ if (token.type === "KEY") {
29
+ const key = token.value;
30
+ const valueToken = tokens[i + 2]; //i+1 colon
31
+ if (valueToken && valueToken.type == "VALUE") {
32
+ switch (key) {
33
+ case "TYPE":
34
+ question.type = valueToken.value;
35
+ currentType = valueToken.value;
36
+ break;
37
+ case "QUESTION":
38
+ if (sentinel === "open") {
39
+ sentinel = "close";
40
+ resultArr.push(question);
41
+ resetQuestion();
42
+ // Need to to thing if things are absent
43
+ }
44
+ question.question = valueToken.value;
45
+ question.id = crypto.randomUUID();
46
+ sentinel = "open";
47
+ break;
48
+ case "ANSWER":
49
+ if (valueToken.value.length > 1) {
50
+ question.answer = valueToken.value.split(",");
51
+ }
52
+ else {
53
+ question.answer = valueToken.value;
54
+ }
55
+ if (question.answer.length == 1 && question.type == undefined) {
56
+ question.type = "MCQ";
57
+ }
58
+ break;
59
+ case "EXPLANATION":
60
+ question.explanation = valueToken.value;
61
+ break;
62
+ }
63
+ i += 3;
64
+ continue;
65
+ }
66
+ }
67
+ if (token.type == "OPTION_KEY") {
68
+ const optionValueToken = tokens[i + 2];
69
+ if (optionValueToken &&
70
+ optionValueToken.type === "OPTION_VALUE") {
71
+ (_a = question.options) === null || _a === void 0 ? void 0 : _a.push({
72
+ key: token.value,
73
+ value: optionValueToken.value
74
+ });
75
+ i += 3;
76
+ continue;
77
+ }
78
+ }
79
+ }
80
+ console.log(resultArr.length);
81
+ return resultArr;
82
+ }
83
+ let input = `
84
+ TYPE: MCQ
85
+ QUESTION: In web design, what is the recommended approach for typography to ensure readability and clarity?
86
+ A. Using a variety of fonts to make the text stand out
87
+ B. Opting for serif fonts for their historical significance and readability
88
+ C. Choosing sans-serif fonts for modern aesthetics
89
+ D. Using the largest font size possible for all text
90
+ ANSWER: B
91
+ EXPLANATION: Serif fonts are often chosen for their historical significance and readability.
92
+ `;
93
+ input = `
94
+ Here are five hard-level MCQ questions based on the provided prompt:
95
+
96
+ QUESTION: Which of the following best describes the primary purpose of a preloader in web design?
97
+ A. To enhance the visual aesthetics of the website
98
+ B. To ensure faster actual loading times of the website
99
+ C. To create the perception of faster loading times through engaging animations or progress indicators
100
+ D. To provide additional information about the website's content
101
+ ANSWER: C
102
+ EXPLANATION: Preloaders are used to create the perception of faster loading times, engaging users with animations or progress indicators while the website content loads in the background.
103
+
104
+ QUESTION: In the context of web design, what does SVG stand for and what is its primary use?
105
+ A. Scalable Vector Graphics, used for defining three-dimensional graphics
106
+ B. Simple Vector Graphics, used for creating basic two-dimensional images
107
+ C. Scalable Vector Graphics, used for defining two-dimensional graphics with interactivity and animation support
108
+ D. Standard Vector Graphics, used for standardizing image formats across different platforms
109
+ ANSWER: C
110
+ EXPLANATION: SVG stands for Scalable Vector Graphics, an XML-based vector image format for two-dimensional graphics with support for interactivity and animation.
111
+
112
+ QUESTION: When designing a website, which structural element is crucial for indicating the primary actions users should take?
113
+ A. Hero section
114
+ B. Feature section
115
+ C. Call to Action (CTA)
116
+ D. Testimonial section
117
+ ANSWER: C
118
+ EXPLANATION: The Call to Action (CTA) section is designed to prompt users to take specific actions, such as signing up, purchasing, or contacting, making it a crucial element in website design.
119
+
120
+ ---
121
+ QUESTION: Which type of user flow is specifically designed to illustrate the sequence of steps a user takes to complete a specific task on a website?
122
+ A. Wire flow
123
+ B. Task flow
124
+ C. Content flow
125
+ D. Navigation flow
126
+ ANSWER: B
127
+ EXPLANATION: Task flow is a type of user flow that illustrates the sequence of steps a user takes to complete a specific task on a website, helping designers understand user interactions and improve the user experience.
128
+
129
+ ---
130
+ QUESTION: In web design, what is the recommended approach for typography to ensure readability and clarity?
131
+ A. Using a variety of fonts to make the text stand out
132
+ B. Opting for serif fonts for their historical significance and readability
133
+ C. Choosing sans-serif fonts for modern aesthetics
134
+ D. Using the largest font size possible for all text
135
+ ANSWER: B
136
+ EXPLANATION: Serif fonts are often chosen for their historical significance and readability, making them a popular choice for body text in web design to ensure clarity and ease of reading.
137
+
138
+ ---`;
139
+ let lex_out = (0, lexer_js_1.lexer)(input);
140
+ // console.log(lex_out);
141
+ console.log(parser(lex_out));
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "skewer-format",
3
+ "version": "1.0.0",
4
+ "description": "New format to store quiz in text format",
5
+ "license": "MIT",
6
+ "author": "sassykumar <sasikumarstu@gamil.com>",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "type": "commonjs",
11
+ "main": "dist/index.js",
12
+ "scripts": {
13
+ "dev": "vite",
14
+ "build": "tsc -b && vite build",
15
+ "lint": "eslint .",
16
+ "preview": "vite preview",
17
+ "prepare": "husky"
18
+ },
19
+ "dependencies": {
20
+ "prettier": "^3.8.3",
21
+ "react": "^19.2.4",
22
+ "react-dom": "^19.2.4"
23
+ },
24
+ "devDependencies": {
25
+ "@babel/core": "^7.29.0",
26
+ "@eslint/js": "^9.39.4",
27
+ "@rolldown/plugin-babel": "^0.2.0",
28
+ "@types/babel__core": "^7.20.5",
29
+ "@types/node": "^24.12.0",
30
+ "@types/react": "^19.2.14",
31
+ "@types/react-dom": "^19.2.3",
32
+ "@vitejs/plugin-react": "^6.0.0",
33
+ "babel-plugin-react-compiler": "^1.0.0",
34
+ "eslint": "^9.39.4",
35
+ "eslint-plugin-react-hooks": "^7.0.1",
36
+ "eslint-plugin-react-refresh": "^0.5.2",
37
+ "globals": "^17.4.0",
38
+ "husky": "^9.1.7",
39
+ "lint-staged": "^17.0.4",
40
+ "typescript": "~5.9.3",
41
+ "typescript-eslint": "^8.56.1",
42
+ "vite": "^8.0.0"
43
+ },
44
+ "lint-staged": {
45
+ "*.{js,ts,tsx,json,css,md}": [
46
+ "prettier --write"
47
+ ],
48
+ "*.{js,ts,tsx}": [
49
+ "eslint --fix --max-warnings=10"
50
+ ]
51
+ }
52
+ }