@gtkx/codegen 1.1.0 → 1.2.1

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 (169) hide show
  1. package/dist/analysis/descriptor-render.d.ts.map +1 -1
  2. package/dist/analysis/descriptor-render.js +14 -10
  3. package/dist/analysis/descriptor-render.js.map +1 -1
  4. package/dist/analysis/descriptor.d.ts +11 -5
  5. package/dist/analysis/descriptor.d.ts.map +1 -1
  6. package/dist/analysis/descriptor.js +25 -9
  7. package/dist/analysis/descriptor.js.map +1 -1
  8. package/dist/analysis/interface-conflicts.d.ts +3 -1
  9. package/dist/analysis/interface-conflicts.d.ts.map +1 -1
  10. package/dist/analysis/interface-conflicts.js +3 -8
  11. package/dist/analysis/interface-conflicts.js.map +1 -1
  12. package/dist/analysis/ts-type.d.ts +3 -2
  13. package/dist/analysis/ts-type.d.ts.map +1 -1
  14. package/dist/analysis/ts-type.js +16 -9
  15. package/dist/analysis/ts-type.js.map +1 -1
  16. package/dist/analysis/type-shape.d.ts +3 -2
  17. package/dist/analysis/type-shape.d.ts.map +1 -1
  18. package/dist/analysis/type-shape.js +2 -1
  19. package/dist/analysis/type-shape.js.map +1 -1
  20. package/dist/compile.d.ts +4 -5
  21. package/dist/compile.d.ts.map +1 -1
  22. package/dist/compile.js +56 -4
  23. package/dist/compile.js.map +1 -1
  24. package/dist/docs/api-reference.d.ts +2 -0
  25. package/dist/docs/api-reference.d.ts.map +1 -1
  26. package/dist/docs/api-reference.js +1 -1
  27. package/dist/docs/api-reference.js.map +1 -1
  28. package/dist/docs/pipeline.d.ts +1 -0
  29. package/dist/docs/pipeline.d.ts.map +1 -1
  30. package/dist/docs/pipeline.js +10 -3
  31. package/dist/docs/pipeline.js.map +1 -1
  32. package/dist/docs/symbol-page.d.ts.map +1 -1
  33. package/dist/docs/symbol-page.js +2 -4
  34. package/dist/docs/symbol-page.js.map +1 -1
  35. package/dist/fingerprint.d.ts +11 -5
  36. package/dist/fingerprint.d.ts.map +1 -1
  37. package/dist/fingerprint.js +22 -19
  38. package/dist/fingerprint.js.map +1 -1
  39. package/dist/gi.d.ts +1 -0
  40. package/dist/gi.d.ts.map +1 -1
  41. package/dist/gi.js +7 -2
  42. package/dist/gi.js.map +1 -1
  43. package/dist/gir/class.d.ts +7 -2
  44. package/dist/gir/class.d.ts.map +1 -1
  45. package/dist/gir/class.js +4 -1
  46. package/dist/gir/class.js.map +1 -1
  47. package/dist/gir/gir-path.d.ts +1 -1
  48. package/dist/gir/gir-path.js +1 -1
  49. package/dist/gir/gir-path.js.map +1 -1
  50. package/dist/gir/library.d.ts +5 -1
  51. package/dist/gir/library.d.ts.map +1 -1
  52. package/dist/gir/library.js +8 -1
  53. package/dist/gir/library.js.map +1 -1
  54. package/dist/gir/parse.d.ts.map +1 -1
  55. package/dist/gir/parse.js +4 -1
  56. package/dist/gir/parse.js.map +1 -1
  57. package/dist/gir/primitives.js +1 -1
  58. package/dist/gir/primitives.js.map +1 -1
  59. package/dist/khronos/args.d.ts.map +1 -1
  60. package/dist/khronos/args.js +8 -6
  61. package/dist/khronos/args.js.map +1 -1
  62. package/dist/khronos/render.d.ts.map +1 -1
  63. package/dist/khronos/render.js +8 -4
  64. package/dist/khronos/render.js.map +1 -1
  65. package/dist/runner.d.ts +2 -0
  66. package/dist/runner.d.ts.map +1 -1
  67. package/dist/runner.js +5 -3
  68. package/dist/runner.js.map +1 -1
  69. package/dist/staging.d.ts.map +1 -1
  70. package/dist/staging.js +1 -1
  71. package/dist/staging.js.map +1 -1
  72. package/dist/store/compile-store.d.ts +0 -1
  73. package/dist/store/compile-store.d.ts.map +1 -1
  74. package/dist/store/compile-store.js +7 -34
  75. package/dist/store/compile-store.js.map +1 -1
  76. package/dist/store/gi/callables.d.ts +2 -4
  77. package/dist/store/gi/callables.d.ts.map +1 -1
  78. package/dist/store/gi/callables.js +22 -7
  79. package/dist/store/gi/callables.js.map +1 -1
  80. package/dist/store/gi/class.d.ts.map +1 -1
  81. package/dist/store/gi/class.js +63 -17
  82. package/dist/store/gi/class.js.map +1 -1
  83. package/dist/store/gi/constant.js +1 -1
  84. package/dist/store/gi/constant.js.map +1 -1
  85. package/dist/store/gi/enum.d.ts.map +1 -1
  86. package/dist/store/gi/enum.js +2 -5
  87. package/dist/store/gi/enum.js.map +1 -1
  88. package/dist/store/gi/gtype-binding.d.ts +2 -1
  89. package/dist/store/gi/gtype-binding.d.ts.map +1 -1
  90. package/dist/store/gi/gtype-binding.js +13 -1
  91. package/dist/store/gi/gtype-binding.js.map +1 -1
  92. package/dist/store/gi/interface.js +4 -4
  93. package/dist/store/gi/interface.js.map +1 -1
  94. package/dist/store/gi/method.d.ts.map +1 -1
  95. package/dist/store/gi/method.js +4 -7
  96. package/dist/store/gi/method.js.map +1 -1
  97. package/dist/store/gi/property-accessor.d.ts +0 -3
  98. package/dist/store/gi/property-accessor.d.ts.map +1 -1
  99. package/dist/store/gi/property-accessor.js +15 -108
  100. package/dist/store/gi/property-accessor.js.map +1 -1
  101. package/dist/store/gi/record-constructor.d.ts.map +1 -1
  102. package/dist/store/gi/record-constructor.js +7 -5
  103. package/dist/store/gi/record-constructor.js.map +1 -1
  104. package/dist/store/gi/record-field-accessor.d.ts +3 -2
  105. package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
  106. package/dist/store/gi/record-field-accessor.js +42 -12
  107. package/dist/store/gi/record-field-accessor.js.map +1 -1
  108. package/dist/store/gi/record.d.ts.map +1 -1
  109. package/dist/store/gi/record.js +5 -9
  110. package/dist/store/gi/record.js.map +1 -1
  111. package/dist/store/gi/return-wrap.js +1 -1
  112. package/dist/store/gi/return-wrap.js.map +1 -1
  113. package/dist/store/gi/signal.d.ts.map +1 -1
  114. package/dist/store/gi/signal.js +27 -6
  115. package/dist/store/gi/signal.js.map +1 -1
  116. package/dist/store/jsx-store.d.ts.map +1 -1
  117. package/dist/store/jsx-store.js +0 -1
  118. package/dist/store/jsx-store.js.map +1 -1
  119. package/dist/store/resolve-store.d.ts.map +1 -1
  120. package/dist/store/resolve-store.js +1 -0
  121. package/dist/store/resolve-store.js.map +1 -1
  122. package/dist/store/store-fs.d.ts +0 -1
  123. package/dist/store/store-fs.d.ts.map +1 -1
  124. package/dist/store/store-fs.js +2 -7
  125. package/dist/store/store-fs.js.map +1 -1
  126. package/dist/xml.d.ts +1 -0
  127. package/dist/xml.d.ts.map +1 -1
  128. package/dist/xml.js +28 -1
  129. package/dist/xml.js.map +1 -1
  130. package/overrides/gobject/object.ts.ejs +2 -0
  131. package/package.json +3 -3
  132. package/src/analysis/descriptor-render.ts +19 -10
  133. package/src/analysis/descriptor.ts +43 -9
  134. package/src/analysis/interface-conflicts.ts +6 -8
  135. package/src/analysis/ts-type.ts +30 -11
  136. package/src/analysis/type-shape.ts +5 -2
  137. package/src/compile.ts +87 -6
  138. package/src/docs/api-reference.ts +3 -1
  139. package/src/docs/pipeline.ts +13 -7
  140. package/src/docs/symbol-page.ts +1 -5
  141. package/src/fingerprint.ts +31 -38
  142. package/src/gi.ts +9 -2
  143. package/src/gir/class.ts +12 -3
  144. package/src/gir/gir-path.ts +1 -1
  145. package/src/gir/library.ts +9 -1
  146. package/src/gir/parse.ts +6 -1
  147. package/src/gir/primitives.ts +1 -1
  148. package/src/khronos/args.ts +9 -6
  149. package/src/khronos/render.ts +8 -6
  150. package/src/runner.ts +7 -3
  151. package/src/staging.ts +1 -3
  152. package/src/store/compile-store.ts +7 -40
  153. package/src/store/gi/callables.ts +30 -11
  154. package/src/store/gi/class.ts +96 -21
  155. package/src/store/gi/constant.ts +1 -1
  156. package/src/store/gi/enum.ts +2 -6
  157. package/src/store/gi/gtype-binding.ts +16 -1
  158. package/src/store/gi/interface.ts +4 -4
  159. package/src/store/gi/method.ts +4 -9
  160. package/src/store/gi/property-accessor.ts +22 -193
  161. package/src/store/gi/record-constructor.ts +7 -5
  162. package/src/store/gi/record-field-accessor.ts +65 -13
  163. package/src/store/gi/record.ts +13 -17
  164. package/src/store/gi/return-wrap.ts +1 -1
  165. package/src/store/gi/signal.ts +36 -13
  166. package/src/store/jsx-store.ts +0 -1
  167. package/src/store/resolve-store.ts +1 -0
  168. package/src/store/store-fs.ts +3 -9
  169. package/src/xml.ts +43 -1
@@ -12,6 +12,14 @@ import { computeRecordFieldSlots } from "./record-layout.js";
12
12
  import { appendWrapperClassRegistration } from "./registration.js";
13
13
  import { isConstructibleRecord } from "./value-marshalable.js";
14
14
 
15
+ type RecordMembersOptions = {
16
+ context: ModuleContext;
17
+ record: GirRecord;
18
+ className: string;
19
+ callables: Callables;
20
+ gtypeExpr: string | undefined;
21
+ };
22
+
15
23
  const isGErrorRecord = (context: ModuleContext, record: GirRecord): boolean =>
16
24
  context.namespace.name === "GLib" && record.glibGetType === "g_error_get_type";
17
25
 
@@ -30,7 +38,8 @@ const generateRecord = (context: ModuleContext, record: GirRecord): void => {
30
38
  };
31
39
 
32
40
  generateBindings(context, callables);
33
- const members = renderRecordMembers(context, record, className, callables);
41
+ const gtypeExpr = renderSourceGtype(context, record);
42
+ const members = renderRecordMembers({ context, record, className, callables, gtypeExpr });
34
43
  const body = indentMembers(members);
35
44
  const heritage = isErrorSubclass ? " extends globalThis.Error" : "";
36
45
  const doc = getDoc(record);
@@ -50,29 +59,16 @@ const generateRecord = (context: ModuleContext, record: GirRecord): void => {
50
59
  });
51
60
  }
52
61
 
53
- const gtypeExpr = renderSourceGtype(context, record);
54
-
55
62
  appendWrapperClassRegistration(context, {
56
63
  className,
57
64
  gtypeExpr,
58
65
  });
59
66
  };
60
67
 
61
- const renderRecordMembers = (
62
- context: ModuleContext,
63
- record: GirRecord,
64
- className: string,
65
- callables: Callables,
66
- ): string[] => {
68
+ const renderRecordMembers = (options: RecordMembersOptions): string[] => {
69
+ const { context, record, className, callables, gtypeExpr } = options;
67
70
  const isErrorSubclass = isGErrorRecord(context, record);
68
-
69
- const { members, claimedNames } = renderPlainTypeMembers({
70
- context,
71
- className,
72
- callables,
73
- hasGtype: record.glibGetType !== undefined,
74
- });
75
-
71
+ const { members, claimedNames } = renderPlainTypeMembers({ context, className, callables, gtypeExpr });
76
72
  members.unshift(renderRecordConstructor(context, { record, className, callables, isErrorSubclass }));
77
73
  const { slots } = computeRecordFieldSlots(context, record.fields, record.isUnion);
78
74
 
@@ -10,7 +10,7 @@ type WrapReturnOptions = {
10
10
  valueExpression: string;
11
11
  };
12
12
 
13
- const BIGINT_CATEGORIES: Set<PrimitiveCategory> = new Set(["gtype", "bigint64", "biguint64"]);
13
+ const BIGINT_CATEGORIES: Set<PrimitiveCategory> = new Set(["gtype", "bigint64", "biguint64", "pointer"]);
14
14
 
15
15
  const wrapReturnValue = (context: ModuleContext, options: WrapReturnOptions): string => {
16
16
  const { ref, isNullable, valueExpression } = options;
@@ -1,5 +1,5 @@
1
1
  import { camelCase, sourceStringLiteral } from "@gtkx/utils";
2
- import type { GirClass } from "../../gir/class.js";
2
+ import type { GirClass, GirSignal } from "../../gir/class.js";
3
3
  import type { GirCallable, GirParameter, GirReturnValue } from "../../gir/parameter.js";
4
4
  import type { GirProperty } from "../../gir/property.js";
5
5
  import type { ModuleContext } from "../../writer/context.js";
@@ -48,6 +48,21 @@ const SIGNAL_HANDLER_TYPE = "(...args: any[]) => any";
48
48
  const SIGNALS_SUFFIX = "Signals";
49
49
  const SIGNAL_EMIT_SUFFIX = "SignalEmit";
50
50
 
51
+ const DEPRECATED_SIGNAL_ALIASES: Map<string, string> = new Map([
52
+ ["addEventListener", "on"],
53
+ ["removeEventListener", "off"],
54
+ ]);
55
+
56
+ const deprecatedAliasDoc = (method: string): string => {
57
+ const replacement = DEPRECATED_SIGNAL_ALIASES.get(method);
58
+
59
+ if (replacement === undefined) {
60
+ return "";
61
+ }
62
+
63
+ return `/** @deprecated Since 1.2. Use \`${replacement}\` instead. Removed in v2. */\n`;
64
+ };
65
+
51
66
  const renderSignalMembers = (context: ModuleContext, klass: GirClass): string[] => {
52
67
  if (klass.glibGetType === undefined) {
53
68
  return [];
@@ -68,7 +83,7 @@ const renderSignalMembers = (context: ModuleContext, klass: GirClass): string[]
68
83
 
69
84
  const connectDefault = isRootObject
70
85
  ? "default:\n throw new globalThis.Error(\"Unknown signal '\" + signal + \"'\");"
71
- : "default:\n return super.connect(signal, handler, isAfter);";
86
+ : "default:\n return super.connect(signal as never, handler as never, isAfter);";
72
87
 
73
88
  const emitDefault = isRootObject
74
89
  ? "default:\n throw new globalThis.Error(\"Unknown signal '\" + sigName + \"'\");"
@@ -124,10 +139,18 @@ const renderSignalMap = (spec: SignalMapSpec): string => {
124
139
  const { context, klass, className, isParentlessObjectSubclass, suffix, renderEntry } = spec;
125
140
  const extendsRefs = signalMapParentRefs(context, klass, isParentlessObjectSubclass, suffix);
126
141
  const extendsClause = extendsRefs.length === 0 ? "" : ` extends ${extendsRefs.join(", ")}`;
142
+ const signals = collectClassSignals(context, klass);
127
143
 
128
- const signalEntries = collectClassSignals(context, klass).map(
129
- (signal) => `${signalDoc(signal)}${sourceStringLiteral(signal.name)}: ${renderEntry(context, signal)};`,
130
- );
144
+ const signalEntries = signals.flatMap((signal) => {
145
+ const value = renderEntry(context, signal);
146
+ const entry = `${signalDoc(signal)}${sourceStringLiteral(signal.name)}: ${value};`;
147
+
148
+ if (!signal.isDetailed) {
149
+ return [entry];
150
+ }
151
+
152
+ return [entry, `[detail: \`${signal.name}::\${string}\`]: ${value};`];
153
+ });
131
154
 
132
155
  const entries = [...signalEntries, ...renderNotifyDetailEntries(context, klass, suffix)];
133
156
 
@@ -191,17 +214,17 @@ const renderSignalConnectInterface = (className: string, isRootObject: boolean):
191
214
  const lines = [
192
215
  `__signals__?: ${map};`,
193
216
  `connect<K extends keyof ${map}>(signal: K, handler: ${map}[K], isAfter?: boolean): number;`,
194
- `connect(signal: string, handler: ${SIGNAL_HANDLER_TYPE}, isAfter?: boolean): number;`,
195
217
  `emit<K extends keyof ${emitMap}>(sigName: K, ...args: ${emitMap}[K]["args"]): ${emitMap}[K]["result"];`,
196
- "emit(sigName: string, ...args: unknown[]): unknown;",
197
218
  ];
198
219
 
199
- if (!isRootObject) {
220
+ if (isRootObject) {
221
+ lines.push("emit(sigName: string, ...args: unknown[]): unknown;");
222
+ } else {
200
223
  const chainable = (methods: string[], trailing: string): void => {
201
224
  for (const method of methods) {
202
225
  lines.push(
226
+ deprecatedAliasDoc(method) +
203
227
  `${method}<K extends keyof ${map}>(signal: K, handler: ${map}[K]${trailing}): this;`,
204
- `${method}(signal: string, handler: ${SIGNAL_HANDLER_TYPE}${trailing}): this;`,
205
228
  );
206
229
  }
207
230
  };
@@ -356,7 +379,7 @@ const renderCallback = (context: ModuleContext, signal: GirCallable): string =>
356
379
  const forEachInterfaceSignal = (
357
380
  context: ModuleContext,
358
381
  klass: GirClass,
359
- consider: (signal: GirCallable) => void,
382
+ consider: (signal: GirSignal) => void,
360
383
  ): void => {
361
384
  for (const iface of resolveInterfaces(context.library, context.namespace.name, klass.implements)) {
362
385
  for (const signal of iface.klass.signals) {
@@ -365,12 +388,12 @@ const forEachInterfaceSignal = (
365
388
  }
366
389
  };
367
390
 
368
- const collectClassSignals = (context: ModuleContext, klass: GirClass): GirCallable[] => {
391
+ const collectClassSignals = (context: ModuleContext, klass: GirClass): GirSignal[] => {
369
392
  const inheritedNames = collectInheritedSignalNames(context, klass);
370
393
  const seen: Set<string> = new Set();
371
- const result: GirCallable[] = [];
394
+ const result: GirSignal[] = [];
372
395
 
373
- const consider = (signal: GirCallable): void => {
396
+ const consider = (signal: GirSignal): void => {
374
397
  const name = camelCase(signal.name);
375
398
 
376
399
  if (!signal.introspectable || inheritedNames.has(name) || seen.has(name)) {
@@ -30,7 +30,6 @@ const writeJsxStore = (
30
30
  peerDependencies: { "@gtkx/gi": "*", "@gtkx/react": "*", react: "*" },
31
31
  }),
32
32
  rawFiles,
33
- requiresEnvReference: true,
34
33
  });
35
34
  };
36
35
 
@@ -28,6 +28,7 @@ const STORE_CONSUMERS: string[] = [
28
28
  "@gtkx/components",
29
29
  "@gtkx/css",
30
30
  "@gtkx/react",
31
+ "@gtkx/runtime",
31
32
  "@gtkx/testing",
32
33
  ];
33
34
 
@@ -50,7 +50,6 @@ type WriteStoreParams = {
50
50
  files: SourceModule[];
51
51
  manifest: Manifest;
52
52
  rawFiles?: RawFile[];
53
- requiresEnvReference?: boolean;
54
53
  };
55
54
 
56
55
  const STORE_DIR_MODE = 0o755;
@@ -98,18 +97,13 @@ const writeStore = (params: WriteStoreParams): void => {
98
97
  };
99
98
 
100
99
  const buildTempStore = (tmp: string, params: WriteStoreParams): void => {
100
+ writePackageJson(tmp, params.manifest);
101
+
101
102
  for (const file of params.files) {
102
103
  writeSourceFile(tmp, file.fileName, file.source);
103
104
  }
104
105
 
105
- compileStore({
106
- storeDir: tmp,
107
- files: params.files,
108
- packageName: params.manifest.name,
109
- ...(params.requiresEnvReference !== undefined && { requiresEnvReference: params.requiresEnvReference }),
110
- });
111
-
112
- writePackageJson(tmp, params.manifest);
106
+ compileStore({ storeDir: tmp, files: params.files, packageName: params.manifest.name });
113
107
  const rawFiles = params.rawFiles ?? [];
114
108
 
115
109
  for (const raw of rawFiles) {
package/src/xml.ts CHANGED
@@ -7,8 +7,12 @@ type XmlFileInput = {
7
7
  parser: XMLParser;
8
8
  label: string;
9
9
  path: string;
10
+ malformedRemedy?: string;
10
11
  };
11
12
 
13
+ const HIGHEST_CONTROL_CODE = 0x1F;
14
+ const LEGAL_CONTROL_CODES: Set<number> = new Set([0x09, 0x0A, 0x0D]);
15
+
12
16
  const createXmlParser = (options: Partial<X2jOptions>): XMLParser =>
13
17
  new XMLParser({
14
18
  ignoreAttributes: false,
@@ -46,13 +50,51 @@ const positionSuffix = (error: unknown): string => {
46
50
  return ` (line ${String(line)}, column ${String(col)})`;
47
51
  };
48
52
 
53
+ const isIllegalControlCode = (code: number): boolean =>
54
+ code <= HIGHEST_CONTROL_CODE && !LEGAL_CONTROL_CODES.has(code);
55
+
56
+ const escapedCode = (code: number): string => `[U+${code.toString(16).toUpperCase().padStart(4, "0")}]`;
57
+
58
+ const escapeControlCodes = (text: string): string => {
59
+ let escaped = "";
60
+
61
+ for (const character of text) {
62
+ const code = character.codePointAt(0) ?? 0;
63
+ escaped += isIllegalControlCode(code) ? escapedCode(code) : character;
64
+ }
65
+
66
+ return escaped;
67
+ };
68
+
69
+ const offendingLine = (xml: string, error: unknown): string => {
70
+ const line = isRecord(error) ? error.line : undefined;
71
+
72
+ if (typeof line !== "number") {
73
+ return "";
74
+ }
75
+
76
+ const text = xml.split("\n")[line - 1];
77
+
78
+ if (text === undefined) {
79
+ return "";
80
+ }
81
+
82
+ return `\n ${escapeControlCodes(text.replace(/^[ \t]+/, "").replace(/\r$/, ""))}`;
83
+ };
84
+
85
+ const remedySuffix = (input: XmlFileInput, xml: string, error: unknown): string => {
86
+ const remedy = input.malformedRemedy;
87
+
88
+ return remedy === undefined ? "" : `${offendingLine(xml, error)}\n${remedy}`;
89
+ };
90
+
49
91
  const assertWellFormed = (input: XmlFileInput, xml: string): void => {
50
92
  try {
51
93
  SyntaxValidator.validate(xml);
52
94
  } catch (error) {
53
95
  throw new Error(
54
96
  `The ${input.label} at ${input.path} is not well-formed XML: ` +
55
- `${errorMessage(error)}${positionSuffix(error)}`,
97
+ `${errorMessage(error)}${positionSuffix(error)}${remedySuffix(input, xml, error)}`,
56
98
  { cause: error },
57
99
  );
58
100
  }