@aster-cloud/aster-lang-ts 1.0.12 → 1.0.14

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.
Files changed (61) hide show
  1. package/dist/scripts/core-ir-json.js +16 -6
  2. package/dist/scripts/core-ir-json.js.map +1 -1
  3. package/dist/src/config/lexicons/de-DE.d.ts.map +1 -1
  4. package/dist/src/config/lexicons/de-DE.js +1 -0
  5. package/dist/src/config/lexicons/de-DE.js.map +1 -1
  6. package/dist/src/config/lexicons/en-US.d.ts.map +1 -1
  7. package/dist/src/config/lexicons/en-US.js +1 -0
  8. package/dist/src/config/lexicons/en-US.js.map +1 -1
  9. package/dist/src/config/lexicons/hi-IN.d.ts.map +1 -1
  10. package/dist/src/config/lexicons/hi-IN.js +1 -0
  11. package/dist/src/config/lexicons/hi-IN.js.map +1 -1
  12. package/dist/src/config/lexicons/identifiers/types.d.ts.map +1 -1
  13. package/dist/src/config/lexicons/identifiers/types.js +5 -3
  14. package/dist/src/config/lexicons/identifiers/types.js.map +1 -1
  15. package/dist/src/config/lexicons/template.d.ts.map +1 -1
  16. package/dist/src/config/lexicons/template.js +2 -0
  17. package/dist/src/config/lexicons/template.js.map +1 -1
  18. package/dist/src/config/lexicons/types.d.ts +15 -0
  19. package/dist/src/config/lexicons/types.d.ts.map +1 -1
  20. package/dist/src/config/lexicons/types.js.map +1 -1
  21. package/dist/src/config/lexicons/zh-CN.d.ts.map +1 -1
  22. package/dist/src/config/lexicons/zh-CN.js +1 -0
  23. package/dist/src/config/lexicons/zh-CN.js.map +1 -1
  24. package/dist/src/config/token-kind.d.ts +2 -0
  25. package/dist/src/config/token-kind.d.ts.map +1 -1
  26. package/dist/src/config/token-kind.js +3 -0
  27. package/dist/src/config/token-kind.js.map +1 -1
  28. package/dist/src/core/interpreter.js +118 -19
  29. package/dist/src/core/interpreter.js.map +1 -1
  30. package/dist/src/frontend/canonicalizer.d.ts.map +1 -1
  31. package/dist/src/frontend/canonicalizer.js +43 -14
  32. package/dist/src/frontend/canonicalizer.js.map +1 -1
  33. package/dist/src/frontend/lexer.d.ts.map +1 -1
  34. package/dist/src/frontend/lexer.js +10 -0
  35. package/dist/src/frontend/lexer.js.map +1 -1
  36. package/dist/src/parser/decl-parser.d.ts.map +1 -1
  37. package/dist/src/parser/decl-parser.js +25 -19
  38. package/dist/src/parser/decl-parser.js.map +1 -1
  39. package/dist/src/parser/expr-stmt-parser.d.ts +9 -0
  40. package/dist/src/parser/expr-stmt-parser.d.ts.map +1 -1
  41. package/dist/src/parser/expr-stmt-parser.js +26 -0
  42. package/dist/src/parser/expr-stmt-parser.js.map +1 -1
  43. package/dist/src/types.d.ts +1 -0
  44. package/dist/src/types.d.ts.map +1 -1
  45. package/dist/src/types.js +3 -0
  46. package/dist/src/types.js.map +1 -1
  47. package/dist/test/unit/audit-57-regression.test.d.ts +2 -0
  48. package/dist/test/unit/audit-57-regression.test.d.ts.map +1 -0
  49. package/dist/test/unit/audit-57-regression.test.js +92 -0
  50. package/dist/test/unit/audit-57-regression.test.js.map +1 -0
  51. package/dist/test/unit/config/lexicons/identifiers/literal-macro.test.js +53 -1
  52. package/dist/test/unit/config/lexicons/identifiers/literal-macro.test.js.map +1 -1
  53. package/dist/test/unit/parser/explicit-block.test.d.ts +2 -0
  54. package/dist/test/unit/parser/explicit-block.test.d.ts.map +1 -0
  55. package/dist/test/unit/parser/explicit-block.test.js +43 -0
  56. package/dist/test/unit/parser/explicit-block.test.js.map +1 -0
  57. package/dist/test/unit/parser/then-localization.test.d.ts +2 -0
  58. package/dist/test/unit/parser/then-localization.test.d.ts.map +1 -0
  59. package/dist/test/unit/parser/then-localization.test.js +147 -0
  60. package/dist/test/unit/parser/then-localization.test.js.map +1 -0
  61. package/package.json +1 -1
@@ -2,7 +2,7 @@ import { describe, it } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { buildIdentifierIndex, validateVocabulary, IdentifierKind, } from '../../../../../src/config/lexicons/identifiers/index.js';
4
4
  import { canonicalize } from '../../../../../src/frontend/canonicalizer.js';
5
- import { ZH_CN, initializeAllBundledLexicons } from '../../../../../src/browser.js';
5
+ import { ZH_CN, HI_IN, EN_US, initializeAllBundledLexicons } from '../../../../../src/browser.js';
6
6
  import { vocabularyRegistry } from '../../../../../src/config/lexicons/identifiers/registry.js';
7
7
  initializeAllBundledLexicons();
8
8
  // 字面量宏(IdentifierKind.LITERAL):canonicalize 时把 localized token 展开成字符串
@@ -74,5 +74,57 @@ describe('字面量宏 IdentifierKind.LITERAL', () => {
74
74
  });
75
75
  assert.equal(validateVocabulary(v).valid, false, '普通 struct canonical 非 ASCII 仍应被拒');
76
76
  });
77
+ // ── 天城文(Hindi)字面量宏触发词 ────────────────────────────────────────
78
+ // 回归:identifier 匹配正则原为 [a-zA-Z_一-龥](ASCII+CJK),把 जागे 切成 ज+ग
79
+ // (丢失元音符号 matra ा/े,属 Unicode Mark \p{M} 而非 Letter \p{L}),导致天城文触发词
80
+ // 永不匹配。修为 [\p{L}_][\p{L}\p{M}\p{Nd}_]* 后 जागे 作为整词匹配并展开。与 Java 引擎
81
+ // isIdentifierPart 纳入 Mark 对齐。动机:Gitanjali #35 印地语 demo。
82
+ it('端到端 canonicalize(Hindi domain 路径):जागे → 英文名句字面量', () => {
83
+ const TENANT = 'gitanjali-t';
84
+ vocabularyRegistry.registerCustom(TENANT, {
85
+ id: 'gitanjali', name: 'Gitanjali', locale: 'hi-IN', version: '1.0.0',
86
+ structs: [], fields: [], functions: [], enumValues: [],
87
+ literals: [{
88
+ localized: 'जागे',
89
+ canonical: 'Into that heaven of freedom, let my country awake',
90
+ kind: IdentifierKind.LITERAL,
91
+ }],
92
+ });
93
+ const out = canonicalize('लौटाएं जागे।', {
94
+ lexicon: HI_IN, domain: 'gitanjali', locale: 'hi-IN', tenantId: TENANT,
95
+ });
96
+ assert.match(out, /"Into that heaven of freedom, let my country awake"/, `天城文触发词应展开成英文字符串字面量,实际: ${out}`);
97
+ assert.doesNotMatch(out, /जागे/, '原天城文 token 不应残留(含元音符号也须整词匹配)');
98
+ });
99
+ it('天城文含元音符号(matra)的多词触发词整词匹配(不被切碎)', () => {
100
+ // निर्भय 含 ि/े 组合记号;स्वर्ग 含 ्/े。确认整词进 index 且能展开。
101
+ const v = {
102
+ id: 'x', name: 'x', locale: 'hi-IN', version: '1.0.0',
103
+ structs: [], fields: [], functions: [], enumValues: [],
104
+ literals: [{ localized: 'निर्भय', canonical: 'fearless', kind: IdentifierKind.LITERAL }],
105
+ };
106
+ const index = buildIdentifierIndex(v);
107
+ assert.equal(index.literals.has('निर्भय'), true, 'निर्भय 整词进 index');
108
+ assert.equal(index.toCanonical.get('निर्भय'), 'fearless', 'toCanonical 存内容');
109
+ });
110
+ // 跨引擎 parity 边界(Codex 审查):identifier 数字部分用 \p{Nd}(十进制)而非 \p{N},
111
+ // 与 Java Character.isDigit 对齐。\p{N} 会含 Nl(罗马数字 Ⅻ)/No(上标 ²)→ Java 在这些
112
+ // 字符处断开而 TS 不断,造成 canonicalize 切分分歧。用一个含 Ⅻ(U+216B, Nl) 的触发词验证:
113
+ // 只有 base(a) 会被当 identifier 匹配,Ⅻ 不粘进来 → 整词触发词 "aⅫ" 不会命中。
114
+ it('数字用 \\p{Nd} 非 \\p{N}:Nl/No(如罗马数字Ⅻ)不粘进 identifier(对齐 Java isDigit)', () => {
115
+ const TENANT = 'nd-parity-t';
116
+ vocabularyRegistry.registerCustom(TENANT, {
117
+ id: 'ndp', name: 'ndp', locale: 'en-US', version: '1.0.0',
118
+ structs: [], fields: [], functions: [], enumValues: [],
119
+ // 触发词含 Ⅻ(罗马数字, category Nl)。若 IDENT_RE 用 \p{N} 会把 "aⅫ" 当整词,
120
+ // 与 Java(在Ⅻ断开) 分歧。用 \p{Nd} 则 Ⅻ 不算 identifier part → 触发词 "aⅫ" 不整词命中。
121
+ literals: [{ localized: 'aⅫ', canonical: 'ROMAN', kind: IdentifierKind.LITERAL }],
122
+ });
123
+ const out = canonicalize('Return aⅫ.', {
124
+ lexicon: EN_US, domain: 'ndp', locale: 'en-US', tenantId: TENANT,
125
+ });
126
+ // 触发词 "aⅫ" 不应被当整词展开(因为 Ⅻ 不是 \p{Nd} → identifier 在 a 后断开)。
127
+ assert.doesNotMatch(out, /ROMAN/, `\\p{Nd} 下 Nl 字符不应粘进 identifier,实际: ${out}`);
128
+ });
77
129
  });
78
130
  //# sourceMappingURL=literal-macro.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"literal-macro.test.js","sourceRoot":"","sources":["../../../../../../test/unit/config/lexicons/identifiers/literal-macro.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"literal-macro.test.js","sourceRoot":"","sources":["../../../../../../test/unit/config/lexicons/identifiers/literal-macro.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=explicit-block.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explicit-block.test.d.ts","sourceRoot":"","sources":["../../../../test/unit/parser/explicit-block.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ // ADR 0028:显式块分隔符 TS 引擎测试(与 Java ExplicitBlockTest 对称)。
2
+ //
3
+ // 核心不变式:显式块(`produce T:stmt. fin`)与缩进块编译到**同一 Core IR**——仅结束方式
4
+ // 不同(DEDENT vs BLOCK_END 词),下游语义一致。默认无 blockDelimiters 时块结束词是普通标识符。
5
+ //
6
+ // 同脚本约束(Codex 交叉审 P1):块结束词必须是所在 lexicon 可 lex 为标识符的词——en-US 配
7
+ // 英文词「fin」(与 Java 测试同配置同源码,证跨引擎输入接受集一致)。
8
+ import { describe, test } from 'node:test';
9
+ import assert from 'node:assert/strict';
10
+ import { compile } from '../../../src/browser.js';
11
+ import { EN_US } from '../../../src/config/lexicons/en-US.js';
12
+ const WITH_FIN = { ...EN_US, id: 'x', name: 'x', blockDelimiters: { end: ['fin'] } };
13
+ /** 去 origin 的 Core IR 结构(span 位置随排版不同,比结构)。 */
14
+ function stripOrigin(core) {
15
+ return JSON.stringify(core, (k, v) => (k === 'origin' ? undefined : v));
16
+ }
17
+ describe('ADR 0028 显式块(explicit block)', () => {
18
+ test('显式块与缩进块编译到同一 Core IR', () => {
19
+ const indented = 'Module Detective.\n\nRule solve given clueA as Bool, produce Text:\n if clueA then return "guilty" else return "innocent".';
20
+ const explicit = 'Module Detective.\n\nRule solve given clueA as Bool, produce Text:if clueA then return "guilty" else return "innocent".fin';
21
+ const ci = compile(indented, { lexicon: WITH_FIN, domain: 'x', tenantId: 'x' });
22
+ const ce = compile(explicit, { lexicon: WITH_FIN, domain: 'x', tenantId: 'x' });
23
+ assert.equal(ci.success, true, JSON.stringify(ci.parseErrors));
24
+ assert.equal(ce.success, true, JSON.stringify(ce.parseErrors));
25
+ assert.equal(stripOrigin(ce.core), stripOrigin(ci.core));
26
+ });
27
+ test('缺省 lexicon(无 blockDelimiters)下块结束词是普通标识符', () => {
28
+ const src = 'Module T.\n\nRule f given fin as Bool, produce Bool:\n return fin.';
29
+ const c = compile(src, { lexicon: EN_US, domain: 'x', tenantId: 'x' });
30
+ assert.equal(c.success, true, JSON.stringify(c.parseErrors)); // 'fin' 作参数名/标识符
31
+ });
32
+ test('块结束词是整词才匹配,含它的更长标识符不被切开', () => {
33
+ const src = 'Module T.\n\nRule f given finish as Bool, produce Bool:\n return finish.';
34
+ const c = compile(src, { lexicon: WITH_FIN, domain: 'x', tenantId: 'x' });
35
+ assert.equal(c.success, true, JSON.stringify(c.parseErrors)); // 'finish' != 'fin' → 标识符
36
+ });
37
+ test('显式块运行:喂入决策线索输出正确分支', () => {
38
+ const src = 'Module Detective.\n\nRule solve given clueA as Bool, produce Text:if clueA then return "guilty" else return "innocent".fin';
39
+ const c = compile(src, { lexicon: WITH_FIN, domain: 'x', tenantId: 'x' });
40
+ assert.equal(c.success, true, JSON.stringify(c.parseErrors));
41
+ });
42
+ });
43
+ //# sourceMappingURL=explicit-block.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explicit-block.test.js","sourceRoot":"","sources":["../../../../test/unit/parser/explicit-block.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=then-localization.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"then-localization.test.d.ts","sourceRoot":"","sources":["../../../../test/unit/parser/then-localization.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * ADR 0029:inline-if 的 then 连接词进入 SemanticTokenKind.THEN,并由四语词法表翻译。
3
+ *
4
+ * 不改 parser 判定逻辑:本地词先经 keyword-translator 归一为英文 `then`,再走现有
5
+ * `isKeyword('then')` 软关键字路径。
6
+ */
7
+ import { describe, it } from 'node:test';
8
+ import assert from 'node:assert/strict';
9
+ import { compile } from '../../../src/browser.js';
10
+ import { canonicalize } from '../../../src/frontend/canonicalizer.js';
11
+ import { lex } from '../../../src/frontend/lexer.js';
12
+ import { parseWithLexicon } from '../../../src/parser.js';
13
+ import { lowerModule } from '../../../src/lower_to_core.js';
14
+ import { EN_US } from '../../../src/config/lexicons/en-US.js';
15
+ import { ZH_CN } from '../../../src/config/lexicons/zh-CN.js';
16
+ import { DE_DE } from '../../../src/config/lexicons/de-DE.js';
17
+ import { HI_IN } from '../../../src/config/lexicons/hi-IN.js';
18
+ import { SemanticTokenKind } from '../../../src/config/token-kind.js';
19
+ const CASES = [
20
+ {
21
+ name: 'en-US',
22
+ lexicon: EN_US,
23
+ thenWord: 'then',
24
+ source: [
25
+ 'Module adr0029.',
26
+ '',
27
+ 'Rule decide given cond as Bool, produce Text:',
28
+ ' Return if cond then "A" else "B".',
29
+ ].join('\n'),
30
+ },
31
+ {
32
+ name: 'zh-CN',
33
+ lexicon: ZH_CN,
34
+ thenWord: '那么',
35
+ source: [
36
+ '模块 adr0029。',
37
+ '',
38
+ '规则 decide 给定 cond 作为 布尔,产出 文本:',
39
+ ' 返回 如果 cond 那么 「A」 否则 「B」。',
40
+ ].join('\n'),
41
+ },
42
+ {
43
+ name: 'de-DE',
44
+ lexicon: DE_DE,
45
+ thenWord: 'dann',
46
+ source: [
47
+ 'Modul adr0029.',
48
+ '',
49
+ 'Regel decide gegeben cond als Boolesch, liefert Text:',
50
+ ' gib zurueck wenn cond dann "A" sonst "B".',
51
+ ].join('\n'),
52
+ },
53
+ {
54
+ name: 'hi-IN',
55
+ lexicon: HI_IN,
56
+ thenWord: 'तो',
57
+ source: [
58
+ 'मॉड्यूल adr0029।',
59
+ '',
60
+ 'नियम decide दिया गया cond रूप में बूलियन, उत्पन्न पाठ:',
61
+ ' लौटाएं यदि cond तो "A" अन्यथा "B"।',
62
+ ].join('\n'),
63
+ },
64
+ ];
65
+ function stripDerived(o) {
66
+ if (Array.isArray(o))
67
+ return o.map(stripDerived);
68
+ if (o && typeof o === 'object') {
69
+ const r = {};
70
+ for (const k of Object.keys(o)) {
71
+ if (k === 'origin' || k === 'span')
72
+ continue;
73
+ r[k] = stripDerived(o[k]);
74
+ }
75
+ return r;
76
+ }
77
+ return o;
78
+ }
79
+ function compileCore(source, lexicon) {
80
+ const result = compile(source, { lexicon });
81
+ assert.equal(result.success, true, `${lexicon.id}: ${JSON.stringify(result.parseErrors ?? result.loweringErrors)}`);
82
+ assert.ok(result.core, `${lexicon.id}: 应产出 Core IR`);
83
+ return result.core;
84
+ }
85
+ function parseWithLexiconCore(source, lexicon) {
86
+ const canonical = canonicalize(source, lexicon);
87
+ const tokens = lex(canonical, lexicon);
88
+ const result = parseWithLexicon(tokens, lexicon);
89
+ const errors = result.diagnostics.filter((d) => d.severity === 'error');
90
+ assert.equal(errors.length, 0, `${lexicon.id}: ${JSON.stringify(errors)}`);
91
+ return lowerModule(result.ast);
92
+ }
93
+ function expectCompiles(source, lexicon) {
94
+ const result = compile(source, { lexicon });
95
+ assert.equal(result.success, true, `${lexicon.id}: ${JSON.stringify(result.parseErrors ?? result.loweringErrors)}`);
96
+ }
97
+ describe('ADR 0029 — then 连接词四语本地化', () => {
98
+ it('四语词法表都提供 THEN 补词', () => {
99
+ assert.equal(EN_US.keywords[SemanticTokenKind.THEN], 'then');
100
+ assert.equal(ZH_CN.keywords[SemanticTokenKind.THEN], '那么');
101
+ assert.equal(DE_DE.keywords[SemanticTokenKind.THEN], 'dann');
102
+ assert.equal(HI_IN.keywords[SemanticTokenKind.THEN], 'तो');
103
+ });
104
+ it('compile():四语 inline-if 产出结构等价 Core IR', () => {
105
+ const expected = stripDerived(compileCore(CASES[0].source, CASES[0].lexicon));
106
+ for (const c of CASES) {
107
+ assert.deepEqual(stripDerived(compileCore(c.source, c.lexicon)), expected, c.name);
108
+ }
109
+ });
110
+ it('parseWithLexicon():四语 inline-if 走通同一翻译链', () => {
111
+ const expected = stripDerived(parseWithLexiconCore(CASES[0].source, CASES[0].lexicon));
112
+ for (const c of CASES) {
113
+ assert.deepEqual(stripDerived(parseWithLexiconCore(c.source, c.lexicon)), expected, c.name);
114
+ }
115
+ });
116
+ it('compile() token translation 把本地 THEN 归一为英文 then', () => {
117
+ for (const c of CASES.slice(1)) {
118
+ const result = compile(c.source, { lexicon: c.lexicon, includeIntermediates: true });
119
+ assert.equal(result.success, true, `${c.name}: ${JSON.stringify(result.parseErrors ?? result.loweringErrors)}`);
120
+ assert.ok(result.tokens?.some((t) => t.value === 'then'), `${c.name}: 应出现翻译后的 then token`);
121
+ assert.equal(result.tokens?.some((t) => t.value === c.thenWord), false, `${c.name}: 本地 then 词不应原样进入 parser`);
122
+ }
123
+ });
124
+ it('THEN 本地词在字段名和参数名位置仍是软关键字', () => {
125
+ expectCompiles('Module m.\n\nDefine Box has then as Int.', EN_US);
126
+ expectCompiles('Module m.\n\nRule echo given then as Int, produce Int:\n Return then.', EN_US);
127
+ expectCompiles('模块 m。\n\n定义 Box 包含 那么 作为 整数。', ZH_CN);
128
+ expectCompiles('模块 m。\n\n规则 echo 给定 那么 作为 整数,产出 整数:\n 返回 那么。', ZH_CN);
129
+ expectCompiles('Modul m.\n\nDefiniere Box hat dann als Ganzzahl.', DE_DE);
130
+ expectCompiles('Modul m.\n\nRegel echo gegeben dann als Ganzzahl, liefert Ganzzahl:\n gib zurueck dann.', DE_DE);
131
+ expectCompiles('मॉड्यूल m।\n\nपरिभाषित Box रखता है तो रूप में पूर्णांक।', HI_IN);
132
+ expectCompiles('मॉड्यूल m।\n\nनियम echo दिया गया तो रूप में पूर्णांक, उत्पन्न पूर्णांक:\n लौटाएं तो।', HI_IN);
133
+ });
134
+ it('连写边界:那么值 不会被切成 then + 值', () => {
135
+ expectCompiles('模块 m。\n\n定义 Box 包含 那么值 作为 整数。', ZH_CN);
136
+ const result = compile([
137
+ '模块 m。',
138
+ '',
139
+ '规则 echo 给定 那么值 作为 整数,产出 整数:',
140
+ ' 返回 那么值。',
141
+ ].join('\n'), { lexicon: ZH_CN, includeIntermediates: true });
142
+ assert.equal(result.success, true, JSON.stringify(result.parseErrors ?? result.loweringErrors));
143
+ assert.ok(result.tokens?.some((t) => t.value === '那么值'), '连写词应作为一个标识符保留');
144
+ assert.equal(result.tokens?.some((t) => t.value === 'then'), false, '那么值 不应产生 then token');
145
+ });
146
+ });
147
+ //# sourceMappingURL=then-localization.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"then-localization.test.js","sourceRoot":"","sources":["../../../../test/unit/parser/then-localization.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aster-cloud/aster-lang-ts",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "Aster CNL (Controlled Natural Language) TypeScript Compiler - Lexer, Parser, AST, Core IR, Type Checker",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",