ipa-core 1.1.1 → 1.1.12
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/generate-config.js +0 -0
- package/generate-conlang.js +0 -0
- package/package.json +3 -3
- package/generate-config.cjs +0 -131
- package/generate-conlang.cjs +0 -125
package/generate-config.js
CHANGED
|
File without changes
|
package/generate-conlang.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ipa-core",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.12",
|
|
4
4
|
"description": "Language-agnostic IPA core with features",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "Cody Bruno",
|
|
7
7
|
"type": "commonjs",
|
|
8
8
|
"bin": {
|
|
9
|
-
"make-conlang": "
|
|
10
|
-
"ipa-init": "
|
|
9
|
+
"make-conlang": "generate-conlang.js",
|
|
10
|
+
"ipa-init": "generate-config.js"
|
|
11
11
|
},
|
|
12
12
|
"main": "index.js",
|
|
13
13
|
"scripts": {
|
package/generate-config.cjs
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// generate-config-cli.cjs
|
|
3
|
-
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
|
|
7
|
-
const core = require('./core.cjs'); // your ES6 exports can stay; if core.js is ES module, you can require with .default
|
|
8
|
-
const modifiers = require('./modifiers.cjs'); // same as above
|
|
9
|
-
|
|
10
|
-
// -----------------------------
|
|
11
|
-
// GROUP IPA SYMBOLS BY TYPE
|
|
12
|
-
// -----------------------------
|
|
13
|
-
function groupByType(core) {
|
|
14
|
-
const groups = {};
|
|
15
|
-
for (const [symbol, data] of Object.entries(core)) {
|
|
16
|
-
const type = data.type || 'other';
|
|
17
|
-
if (!groups[type]) groups[type] = [];
|
|
18
|
-
groups[type].push(symbol);
|
|
19
|
-
}
|
|
20
|
-
return groups;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// -----------------------------
|
|
24
|
-
// WRAP SYMBOL LINES
|
|
25
|
-
// -----------------------------
|
|
26
|
-
function wrapSymbols(symbols, perLine = 12) {
|
|
27
|
-
const lines = [];
|
|
28
|
-
for (let i = 0; i < symbols.length; i += perLine) {
|
|
29
|
-
lines.push('// ' + symbols.slice(i, i + perLine).join(' '));
|
|
30
|
-
}
|
|
31
|
-
return lines.join('\n');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// -----------------------------
|
|
35
|
-
// IPA SECTION
|
|
36
|
-
// -----------------------------
|
|
37
|
-
function generateIPASection(core) {
|
|
38
|
-
const grouped = groupByType(core);
|
|
39
|
-
const sections = Object.entries(grouped).map(([type, symbols]) => {
|
|
40
|
-
symbols.sort((a, b) => a.localeCompare(b));
|
|
41
|
-
return [`// ${type.toUpperCase()}`, wrapSymbols(symbols), ''].join('\n');
|
|
42
|
-
});
|
|
43
|
-
return ['/**', ' * IPA SYMBOL REFERENCE', ' * Copy/paste symbols as needed', '', ...sections].join('\n');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// -----------------------------
|
|
47
|
-
// WRAP MODIFIERS HORIZONTALLY
|
|
48
|
-
// -----------------------------
|
|
49
|
-
function wrapModifiers(modList, maxLineLength = 90) {
|
|
50
|
-
const lines = [];
|
|
51
|
-
let currentLine = '// ';
|
|
52
|
-
modList.forEach((mod, index) => {
|
|
53
|
-
const separator = index === 0 ? '' : ' | ';
|
|
54
|
-
const nextChunk = separator + mod;
|
|
55
|
-
if ((currentLine + nextChunk).length > maxLineLength) {
|
|
56
|
-
lines.push(currentLine);
|
|
57
|
-
currentLine = '// ' + mod;
|
|
58
|
-
} else {
|
|
59
|
-
currentLine += nextChunk;
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
if (currentLine.trim()) lines.push(currentLine);
|
|
63
|
-
return lines.join('\n');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// -----------------------------
|
|
67
|
-
// MODIFIER SECTION
|
|
68
|
-
// -----------------------------
|
|
69
|
-
function generateModifierSection(modifiers) {
|
|
70
|
-
const entries = Object.entries(modifiers);
|
|
71
|
-
entries.sort(([a], [b]) => a.localeCompare(b));
|
|
72
|
-
const formatted = entries.map(([key, data]) => {
|
|
73
|
-
const appliesTo = Array.isArray(data.appliesTo) ? data.appliesTo.join(', ') : data.appliesTo || '';
|
|
74
|
-
return `${key}(${appliesTo})`;
|
|
75
|
-
});
|
|
76
|
-
return ['/**', ' * MODIFIER REFERENCE', ' * modifier(appliesTo)', ' */', '', wrapModifiers(formatted), ''].join('\n');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// -----------------------------
|
|
80
|
-
// ORTHOGRAPHY EXPORT SECTION
|
|
81
|
-
// -----------------------------
|
|
82
|
-
function generateOrthographyExport() {
|
|
83
|
-
const commentedOrthography = [
|
|
84
|
-
'// k: ["k", ["aspirated"]],',
|
|
85
|
-
'// a: ["ɑ", ["more_rounded"]],',
|
|
86
|
-
'// x̱: [',
|
|
87
|
-
'// ["k", ["ejective", "aspirated"]],',
|
|
88
|
-
'// ["x", []]',
|
|
89
|
-
'// ],',
|
|
90
|
-
'// l: ["ɬ"]'
|
|
91
|
-
].join('\n');
|
|
92
|
-
|
|
93
|
-
return [
|
|
94
|
-
'/**',
|
|
95
|
-
' * ORTHOGRAPHY CONFIG',
|
|
96
|
-
' * Use parseConfig() at runtime',
|
|
97
|
-
' *',
|
|
98
|
-
' * Fill in your orthography below; examples are commented out.',
|
|
99
|
-
' */',
|
|
100
|
-
'',
|
|
101
|
-
"const { parseConfig } = require('./parser.cjs');",
|
|
102
|
-
'',
|
|
103
|
-
'const orthography = {',
|
|
104
|
-
commentedOrthography,
|
|
105
|
-
'};',
|
|
106
|
-
'',
|
|
107
|
-
'module.exports = parseConfig(orthography);',
|
|
108
|
-
''
|
|
109
|
-
].join('\n');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// -----------------------------
|
|
113
|
-
// MAIN GENERATOR
|
|
114
|
-
// -----------------------------
|
|
115
|
-
function generateConfig() {
|
|
116
|
-
const content = [
|
|
117
|
-
generateIPASection(core),
|
|
118
|
-
'',
|
|
119
|
-
generateModifierSection(modifiers),
|
|
120
|
-
'',
|
|
121
|
-
generateOrthographyExport()
|
|
122
|
-
].join('\n');
|
|
123
|
-
|
|
124
|
-
const outputPath = path.join(process.cwd(), 'ipa.config.js');
|
|
125
|
-
fs.writeFileSync(outputPath, content, 'utf-8');
|
|
126
|
-
|
|
127
|
-
console.log('✅ ipa.config.js generated with parseConfig() export');
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// RUN
|
|
131
|
-
generateConfig();
|
package/generate-conlang.cjs
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// generate-conlang-cli.cjs
|
|
3
|
-
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const readline = require('readline');
|
|
7
|
-
|
|
8
|
-
const core = require('./core.cjs'); // Use .default if core.js is ES module
|
|
9
|
-
const modifiers = require('./modifiers.cjs'); // Use .default if modifiers.js is ES module
|
|
10
|
-
|
|
11
|
-
/** Pick random element */
|
|
12
|
-
const pickRandom = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
13
|
-
|
|
14
|
-
/** Shuffle array */
|
|
15
|
-
const shuffle = (arr) => {
|
|
16
|
-
for (let i = arr.length - 1; i > 0; i--) {
|
|
17
|
-
const j = Math.floor(Math.random() * (i + 1));
|
|
18
|
-
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
19
|
-
}
|
|
20
|
-
return arr;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/** Prompt helper */
|
|
24
|
-
function prompt(query) {
|
|
25
|
-
const rl = readline.createInterface({
|
|
26
|
-
input: process.stdin,
|
|
27
|
-
output: process.stdout,
|
|
28
|
-
});
|
|
29
|
-
return new Promise((resolve) =>
|
|
30
|
-
rl.question(query, (ans) => {
|
|
31
|
-
rl.close();
|
|
32
|
-
resolve(ans);
|
|
33
|
-
})
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** Generate conlang orthography */
|
|
38
|
-
function generateConlang({ alphabet, mod1Chance, mod2Chance, affricateChance }) {
|
|
39
|
-
const letters = alphabet.split('');
|
|
40
|
-
const usedIPA = new Set();
|
|
41
|
-
const orthography = {};
|
|
42
|
-
const coreKeys = shuffle(Object.keys(core));
|
|
43
|
-
|
|
44
|
-
letters.forEach((letter) => {
|
|
45
|
-
// Pick unused IPA
|
|
46
|
-
let ipaKey;
|
|
47
|
-
while (true) {
|
|
48
|
-
const candidate = pickRandom(coreKeys);
|
|
49
|
-
if (!usedIPA.has(candidate)) {
|
|
50
|
-
ipaKey = candidate;
|
|
51
|
-
usedIPA.add(candidate);
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const baseObj = core[ipaKey];
|
|
57
|
-
const modifiersList = [];
|
|
58
|
-
|
|
59
|
-
// Modifier 1
|
|
60
|
-
if (Math.random() < mod1Chance) {
|
|
61
|
-
const compatible = Object.entries(modifiers).filter(
|
|
62
|
-
([, mod]) => !mod.appliesTo || mod.appliesTo.includes(baseObj?.type)
|
|
63
|
-
);
|
|
64
|
-
if (compatible.length) modifiersList.push(pickRandom(compatible)[0]);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Modifier 2
|
|
68
|
-
if (Math.random() < mod2Chance && modifiersList.length) {
|
|
69
|
-
const compatible = Object.entries(modifiers).filter(
|
|
70
|
-
([key, mod]) =>
|
|
71
|
-
!modifiersList.includes(key) &&
|
|
72
|
-
(!mod.appliesTo || mod.appliesTo.includes(baseObj?.type))
|
|
73
|
-
);
|
|
74
|
-
if (compatible.length) modifiersList.push(pickRandom(compatible)[0]);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Plosive → affricate
|
|
78
|
-
if (baseObj?.features?.manner === 'plosive' && Math.random() < affricateChance) {
|
|
79
|
-
const fricatives = Object.entries(core).filter(
|
|
80
|
-
([, obj]) =>
|
|
81
|
-
obj?.features?.manner === 'fricative' &&
|
|
82
|
-
obj.features.place === baseObj.features.place
|
|
83
|
-
);
|
|
84
|
-
if (fricatives.length) {
|
|
85
|
-
const fricKey = pickRandom(fricatives)[0];
|
|
86
|
-
orthography[letter] = [
|
|
87
|
-
[ipaKey, modifiersList],
|
|
88
|
-
[fricKey, []],
|
|
89
|
-
];
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
orthography[letter] = [ipaKey, modifiersList];
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
return orthography;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** Main async function */
|
|
101
|
-
async function main() {
|
|
102
|
-
const alphabet = (await prompt('Enter alphabet (default a-z): ')) || 'abcdefghijklmnopqrstuvwxyz';
|
|
103
|
-
const mod1 = parseFloat((await prompt('Modifier 1 chance (default 0.33): ')) || '0.33');
|
|
104
|
-
const mod2 = parseFloat((await prompt('Modifier 2 chance (default 0.06): ')) || '0.06');
|
|
105
|
-
const aff = parseFloat((await prompt('Plosive → affricate chance (default 0.1): ')) || '0.1');
|
|
106
|
-
|
|
107
|
-
const orthography = generateConlang({
|
|
108
|
-
alphabet,
|
|
109
|
-
mod1Chance: mod1,
|
|
110
|
-
mod2Chance: mod2,
|
|
111
|
-
affricateChance: aff,
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
const outPath = path.join(process.cwd(), 'generatedConlang.js');
|
|
115
|
-
const lines = Object.entries(orthography).map(
|
|
116
|
-
([l, v]) => ` ${JSON.stringify(l)}:${JSON.stringify(v)}`
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
const content = `/** Generated conlang orthography */\nconst generatedOrthography = {\n${lines.join(',\n')}\n};\nmodule.exports = generatedOrthography;\n`;
|
|
120
|
-
|
|
121
|
-
fs.writeFileSync(outPath, content, 'utf-8');
|
|
122
|
-
console.log('✅ generatedConlang.js written');
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
main();
|