@gtkx/cli 1.5.0 → 2.0.0-beta.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.
- package/README.md +5 -5
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/codegen/freshness.d.ts.map +1 -1
- package/dist/codegen/freshness.js +45 -15
- package/dist/codegen/freshness.js.map +1 -1
- package/dist/codegen/reference.d.ts +17 -0
- package/dist/codegen/reference.d.ts.map +1 -0
- package/dist/codegen/reference.js +31 -0
- package/dist/codegen/reference.js.map +1 -0
- package/dist/codegen/report.d.ts.map +1 -1
- package/dist/codegen/report.js +18 -15
- package/dist/codegen/report.js.map +1 -1
- package/dist/codegen/run-codegen.d.ts +5 -5
- package/dist/codegen/run-codegen.d.ts.map +1 -1
- package/dist/codegen/run-codegen.js +24 -59
- package/dist/codegen/run-codegen.js.map +1 -1
- package/dist/codegen/store-resolver.d.ts +0 -1
- package/dist/codegen/store-resolver.d.ts.map +1 -1
- package/dist/codegen/store-resolver.js +8 -17
- package/dist/codegen/store-resolver.js.map +1 -1
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +6 -22
- package/dist/commands/docs.js.map +1 -1
- package/dist/commands/mcp.d.ts +13 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +68 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/deploy/freedesktop/copyright.d.ts.map +1 -1
- package/dist/deploy/freedesktop/copyright.js +2 -13
- package/dist/deploy/freedesktop/copyright.js.map +1 -1
- package/dist/deploy/freedesktop/xml.d.ts.map +1 -1
- package/dist/deploy/freedesktop/xml.js +21 -25
- package/dist/deploy/freedesktop/xml.js.map +1 -1
- package/dist/deploy/node-runtime/license.d.ts.map +1 -1
- package/dist/deploy/node-runtime/license.js +2 -9
- package/dist/deploy/node-runtime/license.js.map +1 -1
- package/dist/deploy/notices/gtkx.js +1 -1
- package/dist/deploy/notices/gtkx.js.map +1 -1
- package/dist/deploy/notices/libraries.d.ts.map +1 -1
- package/dist/deploy/notices/libraries.js +2 -1
- package/dist/deploy/notices/libraries.js.map +1 -1
- package/dist/deploy/notices/packages.d.ts.map +1 -1
- package/dist/deploy/notices/packages.js +3 -10
- package/dist/deploy/notices/packages.js.map +1 -1
- package/dist/deploy/payload/copy-tree.d.ts.map +1 -1
- package/dist/deploy/payload/copy-tree.js +3 -3
- package/dist/deploy/payload/copy-tree.js.map +1 -1
- package/dist/deploy/payload/stage.d.ts.map +1 -1
- package/dist/deploy/payload/stage.js +1 -3
- package/dist/deploy/payload/stage.js.map +1 -1
- package/dist/deploy/settings/build-manifest.d.ts.map +1 -1
- package/dist/deploy/settings/build-manifest.js +4 -15
- package/dist/deploy/settings/build-manifest.js.map +1 -1
- package/dist/deploy/settings/libraries.d.ts.map +1 -1
- package/dist/deploy/settings/libraries.js +2 -21
- package/dist/deploy/settings/libraries.js.map +1 -1
- package/dist/deploy/settings/paths.d.ts +1 -2
- package/dist/deploy/settings/paths.d.ts.map +1 -1
- package/dist/deploy/settings/paths.js +5 -15
- package/dist/deploy/settings/paths.js.map +1 -1
- package/dist/deploy/settings/screenshots.d.ts.map +1 -1
- package/dist/deploy/settings/screenshots.js +6 -31
- package/dist/deploy/settings/screenshots.js.map +1 -1
- package/dist/deploy/targets/flatpak-pnpm.js +4 -4
- package/dist/deploy/targets/flatpak-pnpm.js.map +1 -1
- package/dist/deploy/targets/flatpak-source.d.ts.map +1 -1
- package/dist/deploy/targets/flatpak-source.js +4 -4
- package/dist/deploy/targets/flatpak-source.js.map +1 -1
- package/dist/deploy/targets/flatpak-sources.js +1 -1
- package/dist/deploy/targets/flatpak-sources.js.map +1 -1
- package/dist/deploy/tools.d.ts.map +1 -1
- package/dist/deploy/tools.js +1 -3
- package/dist/deploy/tools.js.map +1 -1
- package/dist/dev/runner-main.js +1 -1
- package/dist/dev/runner-main.js.map +1 -1
- package/dist/dev/schema-dir.d.ts +1 -1
- package/dist/dev/schema-dir.d.ts.map +1 -1
- package/dist/dev/schema-dir.js +2 -4
- package/dist/dev/schema-dir.js.map +1 -1
- package/dist/i18n/catalogs.d.ts.map +1 -1
- package/dist/i18n/catalogs.js +2 -1
- package/dist/i18n/catalogs.js.map +1 -1
- package/dist/i18n/metadata-templates.d.ts.map +1 -1
- package/dist/i18n/metadata-templates.js +2 -1
- package/dist/i18n/metadata-templates.js.map +1 -1
- package/dist/i18n/source-messages.d.ts +3 -21
- package/dist/i18n/source-messages.d.ts.map +1 -1
- package/dist/i18n/source-messages.js +66 -85
- package/dist/i18n/source-messages.js.map +1 -1
- package/dist/i18n/types.d.ts +6 -7
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/i18n/types.js +83 -96
- package/dist/i18n/types.js.map +1 -1
- package/dist/internal/agent-rules.d.ts +7 -0
- package/dist/internal/agent-rules.d.ts.map +1 -0
- package/dist/internal/agent-rules.js +106 -0
- package/dist/internal/agent-rules.js.map +1 -0
- package/dist/internal/docs-elements.d.ts +8 -0
- package/dist/internal/docs-elements.d.ts.map +1 -0
- package/dist/internal/docs-elements.js +12 -0
- package/dist/internal/docs-elements.js.map +1 -0
- package/dist/internal/icon-path.d.ts.map +1 -1
- package/dist/internal/icon-path.js +5 -16
- package/dist/internal/icon-path.js.map +1 -1
- package/dist/internal/source-imports.d.ts.map +1 -1
- package/dist/internal/source-imports.js +10 -42
- package/dist/internal/source-imports.js.map +1 -1
- package/dist/mcp/client-config.d.ts +22 -0
- package/dist/mcp/client-config.d.ts.map +1 -0
- package/dist/mcp/client-config.js +94 -0
- package/dist/mcp/client-config.js.map +1 -0
- package/dist/settings/render.d.ts +0 -1
- package/dist/settings/render.d.ts.map +1 -1
- package/dist/settings/render.js +1 -11
- package/dist/settings/render.js.map +1 -1
- package/dist/settings/schema.d.ts +2 -2
- package/dist/settings/schema.d.ts.map +1 -1
- package/dist/settings/schema.js +21 -62
- package/dist/settings/schema.js.map +1 -1
- package/dist/vite-plugins/asset-imports.d.ts +1 -2
- package/dist/vite-plugins/asset-imports.d.ts.map +1 -1
- package/dist/vite-plugins/asset-imports.js +19 -32
- package/dist/vite-plugins/asset-imports.js.map +1 -1
- package/dist/vite-plugins/asset-specifier.d.ts +1 -3
- package/dist/vite-plugins/asset-specifier.d.ts.map +1 -1
- package/dist/vite-plugins/asset-specifier.js +1 -4
- package/dist/vite-plugins/asset-specifier.js.map +1 -1
- package/dist/vite-plugins/i18n.d.ts.map +1 -1
- package/dist/vite-plugins/i18n.js +2 -1
- package/dist/vite-plugins/i18n.js.map +1 -1
- package/dist/vite-plugins/index.js +2 -2
- package/dist/vite-plugins/index.js.map +1 -1
- package/dist/vite-plugins/resources.d.ts.map +1 -1
- package/dist/vite-plugins/resources.js +31 -96
- package/dist/vite-plugins/resources.js.map +1 -1
- package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
- package/dist/vite-plugins/settings-worker-env.js +1 -3
- package/dist/vite-plugins/settings-worker-env.js.map +1 -1
- package/dist/vite-plugins/settings.d.ts +1 -2
- package/dist/vite-plugins/settings.d.ts.map +1 -1
- package/dist/vite-plugins/settings.js +8 -13
- package/dist/vite-plugins/settings.js.map +1 -1
- package/dist/vite-plugins/undeclared-library.d.ts.map +1 -1
- package/dist/vite-plugins/undeclared-library.js +10 -13
- package/dist/vite-plugins/undeclared-library.js.map +1 -1
- package/dist/vite-plugins/worker.d.ts.map +1 -1
- package/dist/vite-plugins/worker.js +0 -1
- package/dist/vite-plugins/worker.js.map +1 -1
- package/package.json +21 -14
- package/src/cli.ts +5 -0
- package/src/codegen/freshness.ts +66 -16
- package/src/codegen/reference.ts +52 -0
- package/src/codegen/report.ts +16 -17
- package/src/codegen/run-codegen.ts +31 -91
- package/src/codegen/store-resolver.ts +8 -24
- package/src/commands/docs.ts +6 -36
- package/src/commands/mcp.ts +81 -0
- package/src/deploy/freedesktop/copyright.ts +2 -14
- package/src/deploy/freedesktop/xml.ts +24 -32
- package/src/deploy/node-runtime/license.ts +2 -8
- package/src/deploy/notices/gtkx.ts +1 -1
- package/src/deploy/notices/libraries.ts +2 -1
- package/src/deploy/notices/packages.ts +3 -11
- package/src/deploy/payload/copy-tree.ts +3 -4
- package/src/deploy/payload/stage.ts +2 -6
- package/src/deploy/settings/build-manifest.ts +4 -16
- package/src/deploy/settings/libraries.ts +1 -25
- package/src/deploy/settings/paths.ts +6 -16
- package/src/deploy/settings/screenshots.ts +8 -46
- package/src/deploy/targets/flatpak-pnpm.ts +4 -4
- package/src/deploy/targets/flatpak-source.ts +4 -4
- package/src/deploy/targets/flatpak-sources.ts +1 -1
- package/src/deploy/tools.ts +1 -3
- package/src/dev/runner-main.ts +1 -1
- package/src/dev/schema-dir.ts +2 -4
- package/src/i18n/catalogs.ts +2 -1
- package/src/i18n/metadata-templates.ts +2 -1
- package/src/i18n/source-messages.ts +77 -115
- package/src/i18n/types.ts +97 -131
- package/src/internal/agent-rules.ts +135 -0
- package/src/internal/docs-elements.ts +21 -0
- package/src/internal/icon-path.ts +6 -19
- package/src/internal/source-imports.ts +14 -50
- package/src/mcp/client-config.ts +130 -0
- package/src/settings/render.ts +1 -13
- package/src/settings/schema.ts +19 -81
- package/src/vite-plugins/asset-imports.ts +20 -44
- package/src/vite-plugins/asset-specifier.ts +0 -5
- package/src/vite-plugins/i18n.ts +2 -1
- package/src/vite-plugins/index.ts +2 -2
- package/src/vite-plugins/resources.ts +36 -139
- package/src/vite-plugins/settings-worker-env.ts +1 -3
- package/src/vite-plugins/settings.ts +11 -19
- package/src/vite-plugins/undeclared-library.ts +14 -20
- package/src/vite-plugins/worker.ts +0 -1
- package/dist/i18n/binding-extractor.d.ts +0 -30
- package/dist/i18n/binding-extractor.d.ts.map +0 -1
- package/dist/i18n/binding-extractor.js +0 -1324
- package/dist/i18n/binding-extractor.js.map +0 -1
- package/dist/i18n/extractor-plugin.d.ts +0 -8
- package/dist/i18n/extractor-plugin.d.ts.map +0 -1
- package/dist/i18n/extractor-plugin.js +0 -247
- package/dist/i18n/extractor-plugin.js.map +0 -1
- package/dist/internal/data-dir.d.ts +0 -4
- package/dist/internal/data-dir.d.ts.map +0 -1
- package/dist/internal/data-dir.js +0 -52
- package/dist/internal/data-dir.js.map +0 -1
- package/src/i18n/binding-extractor.ts +0 -1969
- package/src/i18n/extractor-plugin.ts +0 -413
- package/src/internal/data-dir.ts +0 -70
|
@@ -2,21 +2,23 @@ import { runCodegen as runCodegenCore } from "@gtkx/codegen";
|
|
|
2
2
|
import { getShadowingStorePaths, sweepProjectStaging } from "@gtkx/codegen/internal";
|
|
3
3
|
import { type Config, loadConfig } from "@gtkx/config";
|
|
4
4
|
import {
|
|
5
|
+
isAgentRulesEnabled,
|
|
5
6
|
resolveElementComponents,
|
|
6
7
|
resolveElementProps,
|
|
7
8
|
resolveLazyElements,
|
|
8
9
|
resolveOmittedProps,
|
|
9
10
|
} from "@gtkx/config/internal";
|
|
10
|
-
import { info
|
|
11
|
+
import { info } from "@gtkx/utils";
|
|
11
12
|
import { existsSync, rmSync } from "node:fs";
|
|
12
13
|
import { join, resolve } from "node:path";
|
|
13
14
|
import { resolveCatalogProject, synchronizeCatalogs } from "../i18n/catalogs.js";
|
|
14
15
|
import { extractSourceCatalog } from "../i18n/source-messages.js";
|
|
15
|
-
import { emitI18nTypes } from "../i18n/types.js";
|
|
16
|
-
import {
|
|
16
|
+
import { clearI18nTypes, emitI18nTypes } from "../i18n/types.js";
|
|
17
|
+
import { upsertAgentRules } from "../internal/agent-rules.js";
|
|
17
18
|
import { discoverSourceFiles } from "../internal/source-imports.js";
|
|
18
19
|
import { emitSchemaEnv } from "../settings/schema.js";
|
|
19
20
|
import { type CodegenInputs, isCodegenStale, resolveCodegenInputs } from "./freshness.js";
|
|
21
|
+
import { type ReferenceResult, writeReference } from "./reference.js";
|
|
20
22
|
import { type CodegenContext, type CodegenStore, resolveCodegenContext } from "./store-resolver.js";
|
|
21
23
|
|
|
22
24
|
type RunCodegenOptions = {
|
|
@@ -37,12 +39,11 @@ type RunCodegenResult = {
|
|
|
37
39
|
isRegenerated: boolean;
|
|
38
40
|
namespaces: number;
|
|
39
41
|
intrinsicElements: number;
|
|
40
|
-
notices: string[];
|
|
41
42
|
duration: number;
|
|
42
|
-
girPath
|
|
43
|
-
configFile
|
|
44
|
-
libraries
|
|
45
|
-
|
|
43
|
+
girPath: string[];
|
|
44
|
+
configFile: string;
|
|
45
|
+
libraries: string[];
|
|
46
|
+
reference?: ReferenceResult | undefined;
|
|
46
47
|
};
|
|
47
48
|
|
|
48
49
|
type CodegenOptionsInput = {
|
|
@@ -50,10 +51,6 @@ type CodegenOptionsInput = {
|
|
|
50
51
|
libraries: string[];
|
|
51
52
|
girPath: string[];
|
|
52
53
|
elements: Config["elements"];
|
|
53
|
-
isByteArrayTyped: boolean;
|
|
54
|
-
isValueUnwrapped: boolean;
|
|
55
|
-
isFinishTrimmed: boolean;
|
|
56
|
-
isInoutInPlace: boolean;
|
|
57
54
|
};
|
|
58
55
|
|
|
59
56
|
type PreparedCodegen = CodegenInputs & { isForced: boolean };
|
|
@@ -64,14 +61,6 @@ type EnsureGeneratedOptions = {
|
|
|
64
61
|
shouldPreserveI18nMetadata?: boolean | undefined;
|
|
65
62
|
};
|
|
66
63
|
|
|
67
|
-
type RunOptionsInput = {
|
|
68
|
-
root: string;
|
|
69
|
-
mode: string | undefined;
|
|
70
|
-
inputs: CodegenInputs | null;
|
|
71
|
-
resolved: LoadedConfig;
|
|
72
|
-
shouldPreserveI18nMetadata: boolean | undefined;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
64
|
const GIR_PATH_MISSING_MESSAGE =
|
|
76
65
|
"No GIR search paths available. Install gobject-introspection " +
|
|
77
66
|
"(Linux: `sudo dnf install gobject-introspection-devel` or `sudo apt install libgirepository1.0-dev`), " +
|
|
@@ -88,13 +77,9 @@ const removeShadowingStores = (cwd: string): void => {
|
|
|
88
77
|
removeStores(getShadowingStorePaths(cwd));
|
|
89
78
|
};
|
|
90
79
|
|
|
91
|
-
const codegenOptions = ({ store, libraries, girPath, elements
|
|
80
|
+
const codegenOptions = ({ store, libraries, girPath, elements }: CodegenOptionsInput) => ({
|
|
92
81
|
libraries,
|
|
93
82
|
girPath,
|
|
94
|
-
isByteArrayTyped: future.isByteArrayTyped,
|
|
95
|
-
isValueUnwrapped: future.isValueUnwrapped,
|
|
96
|
-
isFinishTrimmed: future.isFinishTrimmed,
|
|
97
|
-
isInoutInPlace: future.isInoutInPlace,
|
|
98
83
|
gi: {
|
|
99
84
|
storeDir: store.giStoreDir,
|
|
100
85
|
linkDir: store.giLinkDir,
|
|
@@ -108,50 +93,30 @@ const codegenOptions = ({ store, libraries, girPath, elements, ...future }: Code
|
|
|
108
93
|
linkDir: store.jsxLinkDir,
|
|
109
94
|
version: store.react.version,
|
|
110
95
|
},
|
|
111
|
-
reactSubexports: store.react?.subexports ?? [],
|
|
112
96
|
userComponents: resolveElementComponents(elements),
|
|
113
97
|
userProps: resolveElementProps(elements),
|
|
114
98
|
userLazyElements: resolveLazyElements(elements),
|
|
115
99
|
userOmittedProps: resolveOmittedProps(elements),
|
|
116
100
|
});
|
|
117
101
|
|
|
118
|
-
const enabledFutureFlags = (config: Config): string[] =>
|
|
119
|
-
Object.entries(config.future ?? {})
|
|
120
|
-
.filter(([, value]) => value === true)
|
|
121
|
-
.map(([name]) => name);
|
|
122
|
-
|
|
123
102
|
const disabledCodegenResult = (configFile: string): RunCodegenResult => ({
|
|
124
103
|
isRegenerated: false,
|
|
125
104
|
namespaces: 0,
|
|
126
105
|
intrinsicElements: 0,
|
|
127
|
-
notices: [],
|
|
128
106
|
duration: 0,
|
|
129
107
|
girPath: [],
|
|
130
108
|
configFile,
|
|
131
109
|
libraries: [],
|
|
132
110
|
});
|
|
133
111
|
|
|
134
|
-
const warnNotices = (notices: string[]): void => {
|
|
135
|
-
for (const notice of notices) {
|
|
136
|
-
warn(notice);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const regeneratedStorePaths = (store: CodegenStore): string[] => {
|
|
141
|
-
if (store.react === null) {
|
|
142
|
-
return [store.giStoreDir, store.giLinkDir];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return [store.giStoreDir, store.giLinkDir, store.jsxStoreDir, store.jsxLinkDir];
|
|
146
|
-
};
|
|
147
|
-
|
|
148
112
|
const clearGeneratedStores = (store: CodegenStore): void => {
|
|
149
|
-
removeStores(
|
|
113
|
+
removeStores(
|
|
114
|
+
store.react === null
|
|
115
|
+
? [store.giStoreDir, store.giLinkDir]
|
|
116
|
+
: [store.giStoreDir, store.giLinkDir, store.jsxStoreDir, store.jsxLinkDir],
|
|
117
|
+
);
|
|
150
118
|
};
|
|
151
119
|
|
|
152
|
-
const resolveLoadedConfig = async (options: RunCodegenOptions, cwd: string): Promise<LoadedConfig> =>
|
|
153
|
-
options.resolved ?? (await loadConfig(cwd, { mode: options.mode }));
|
|
154
|
-
|
|
155
120
|
const prepareCodegen = (options: RunCodegenOptions, cwd: string, config: Config): PreparedCodegen => {
|
|
156
121
|
const { girPath, libraries, store } = options.inputs ?? resolveCodegenInputs(cwd, config);
|
|
157
122
|
|
|
@@ -166,9 +131,9 @@ const prepareCodegen = (options: RunCodegenOptions, cwd: string, config: Config)
|
|
|
166
131
|
|
|
167
132
|
const runCodegen = async (options: RunCodegenOptions = {}): Promise<RunCodegenResult> => {
|
|
168
133
|
const cwd = options.cwd ?? process.cwd();
|
|
169
|
-
const { config, configFile } = await
|
|
134
|
+
const { config, configFile } = options.resolved ?? (await loadConfig(cwd, { mode: options.mode }));
|
|
170
135
|
await syncI18n(cwd, config.applicationId, options.shouldPreserveI18nMetadata);
|
|
171
|
-
|
|
136
|
+
emitSchemaEnv(cwd);
|
|
172
137
|
|
|
173
138
|
if (config.codegen === false) {
|
|
174
139
|
removeShadowingStores(cwd);
|
|
@@ -183,31 +148,25 @@ const runCodegen = async (options: RunCodegenOptions = {}): Promise<RunCodegenRe
|
|
|
183
148
|
}
|
|
184
149
|
|
|
185
150
|
const result = await runCodegenCore({
|
|
186
|
-
...codegenOptions({
|
|
187
|
-
store,
|
|
188
|
-
libraries,
|
|
189
|
-
girPath,
|
|
190
|
-
elements: config.elements,
|
|
191
|
-
isByteArrayTyped: config.future?.v2ByteArrays === true,
|
|
192
|
-
isValueUnwrapped: config.future?.v2ValueReturns === true,
|
|
193
|
-
isFinishTrimmed: config.future?.v2FinishResults === true,
|
|
194
|
-
isInoutInPlace: config.future?.v2InoutReturns === true,
|
|
195
|
-
}),
|
|
151
|
+
...codegenOptions({ store, libraries, girPath, elements: config.elements }),
|
|
196
152
|
isForced,
|
|
197
153
|
});
|
|
198
154
|
|
|
199
|
-
|
|
155
|
+
const reference = await writeReference({ root: cwd, config, girPath, libraries, isForced });
|
|
156
|
+
|
|
157
|
+
if (isAgentRulesEnabled(config)) {
|
|
158
|
+
upsertAgentRules(cwd);
|
|
159
|
+
}
|
|
200
160
|
|
|
201
161
|
return {
|
|
202
162
|
isRegenerated: result.isRegenerated,
|
|
203
163
|
namespaces: result.namespaces,
|
|
204
164
|
intrinsicElements: result.intrinsicElements,
|
|
205
|
-
notices: result.notices,
|
|
206
165
|
duration: result.duration,
|
|
207
166
|
girPath,
|
|
208
167
|
configFile,
|
|
209
168
|
libraries,
|
|
210
|
-
|
|
169
|
+
reference,
|
|
211
170
|
};
|
|
212
171
|
};
|
|
213
172
|
|
|
@@ -219,16 +178,16 @@ const syncI18n = async (
|
|
|
219
178
|
const project = resolveCatalogProject(root, applicationId);
|
|
220
179
|
|
|
221
180
|
if (project === null) {
|
|
222
|
-
|
|
181
|
+
clearI18nTypes(root);
|
|
223
182
|
|
|
224
183
|
return;
|
|
225
184
|
}
|
|
226
185
|
|
|
227
186
|
const srcDir = join(root, "src");
|
|
228
187
|
const sourceFiles = discoverSourceFiles(existsSync(srcDir) ? srcDir : root);
|
|
229
|
-
|
|
188
|
+
await extractSourceCatalog(project, sourceFiles, shouldPreserveMetadataMessages);
|
|
230
189
|
synchronizeCatalogs(project);
|
|
231
|
-
emitI18nTypes(root
|
|
190
|
+
await emitI18nTypes(root);
|
|
232
191
|
};
|
|
233
192
|
|
|
234
193
|
const isCodegenDisabled = async (cwd: string, mode?: string): Promise<boolean> => {
|
|
@@ -241,11 +200,6 @@ const isCodegenDisabled = async (cwd: string, mode?: string): Promise<boolean> =
|
|
|
241
200
|
}
|
|
242
201
|
};
|
|
243
202
|
|
|
244
|
-
const syncSchemaEnv = (cwd: string, isV2ResourceImports = false): void => {
|
|
245
|
-
const dataDir = isV2ResourceImports ? null : resolveDataDir(cwd);
|
|
246
|
-
emitSchemaEnv(cwd, dataDir, isV2ResourceImports);
|
|
247
|
-
};
|
|
248
|
-
|
|
249
203
|
const resolveInputsOrNull = (cwd: string, config: Config): CodegenInputs | null => {
|
|
250
204
|
try {
|
|
251
205
|
return resolveCodegenInputs(cwd, config);
|
|
@@ -264,20 +218,6 @@ const maybeAnnounceStale = (shouldAnnounce: boolean | undefined, inputs: Codegen
|
|
|
264
218
|
}
|
|
265
219
|
};
|
|
266
220
|
|
|
267
|
-
const getRunOptions = ({
|
|
268
|
-
root,
|
|
269
|
-
mode,
|
|
270
|
-
inputs,
|
|
271
|
-
resolved,
|
|
272
|
-
shouldPreserveI18nMetadata,
|
|
273
|
-
}: RunOptionsInput): RunCodegenOptions => {
|
|
274
|
-
if (inputs === null) {
|
|
275
|
-
return { cwd: root, mode, resolved, shouldPreserveI18nMetadata };
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return { cwd: root, mode, inputs, resolved, shouldPreserveI18nMetadata };
|
|
279
|
-
};
|
|
280
|
-
|
|
281
221
|
const isPreflightSkipped = (options: EnsureGeneratedOptions): boolean =>
|
|
282
222
|
options.shouldAnnounce === true && process.env.GTKX_DISABLE_PREFLIGHT === "1";
|
|
283
223
|
|
|
@@ -298,13 +238,13 @@ const generate = async (context: CodegenContext, options: EnsureGeneratedOptions
|
|
|
298
238
|
maybeAnnounceStale(options.shouldAnnounce, inputs);
|
|
299
239
|
const resolved = { config: context.config, configFile: context.configFile };
|
|
300
240
|
|
|
301
|
-
const result = await runCodegen(
|
|
302
|
-
|
|
241
|
+
const result = await runCodegen({
|
|
242
|
+
cwd: context.root,
|
|
303
243
|
mode: options.mode,
|
|
304
|
-
inputs,
|
|
305
244
|
resolved,
|
|
306
245
|
shouldPreserveI18nMetadata: options.shouldPreserveI18nMetadata,
|
|
307
|
-
|
|
246
|
+
...(inputs !== null && { inputs }),
|
|
247
|
+
});
|
|
308
248
|
|
|
309
249
|
return result.isRegenerated;
|
|
310
250
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveStore } from "@gtkx/codegen";
|
|
2
2
|
import { type Config, loadConfig } from "@gtkx/config";
|
|
3
|
-
import { existsSync
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
@@ -16,39 +16,23 @@ type CodegenStore = {
|
|
|
16
16
|
|
|
17
17
|
type CodegenReactPackage = {
|
|
18
18
|
version: string;
|
|
19
|
-
subexports: string[];
|
|
20
19
|
};
|
|
21
20
|
|
|
22
|
-
type ResolvedPackage = { dir: string; version: string };
|
|
23
|
-
|
|
24
21
|
type CodegenContext = {
|
|
25
22
|
root: string;
|
|
26
23
|
config: Config;
|
|
27
24
|
configFile: string;
|
|
28
25
|
};
|
|
29
26
|
|
|
30
|
-
const
|
|
31
|
-
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { version?: string };
|
|
32
|
-
|
|
33
|
-
return parsed.version ?? "0.0.0";
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const resolvePackage = (require: NodeJS.Require, dir: string, packageName: string): ResolvedPackage | null => {
|
|
27
|
+
const hasPackage = (require: NodeJS.Require, dir: string, packageName: string): boolean => {
|
|
37
28
|
try {
|
|
38
|
-
|
|
29
|
+
require.resolve(`${packageName}/package.json`);
|
|
39
30
|
|
|
40
|
-
return
|
|
31
|
+
return true;
|
|
41
32
|
} catch {
|
|
42
33
|
const unscoped = packageName.replace(/^@[^/]+\//, "");
|
|
43
|
-
const workspacePkg = join(dir, "packages", unscoped, "package.json");
|
|
44
|
-
|
|
45
|
-
if (!existsSync(workspacePkg)) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const real = realpathSync(workspacePkg);
|
|
50
34
|
|
|
51
|
-
return
|
|
35
|
+
return existsSync(join(dir, "packages", unscoped, "package.json"));
|
|
52
36
|
}
|
|
53
37
|
};
|
|
54
38
|
|
|
@@ -57,12 +41,12 @@ const siblingStore = (giDir: string): string => join(dirname(giDir), "jsx");
|
|
|
57
41
|
const resolveCodegenStore = (dir: string): CodegenStore => {
|
|
58
42
|
const require = createRequire(pathToFileURL(join(dir, "__gtkx_resolver__.js")).href);
|
|
59
43
|
|
|
60
|
-
if (
|
|
44
|
+
if (!hasPackage(require, dir, "@gtkx/native")) {
|
|
61
45
|
throw new Error("Cannot resolve @gtkx/native from the project; is it installed?");
|
|
62
46
|
}
|
|
63
47
|
|
|
64
48
|
const store = resolveStore(dir);
|
|
65
|
-
const hasReactRuntime =
|
|
49
|
+
const hasReactRuntime = hasPackage(require, dir, "react");
|
|
66
50
|
|
|
67
51
|
return {
|
|
68
52
|
giStoreDir: store.gi.storeDir,
|
|
@@ -72,7 +56,7 @@ const resolveCodegenStore = (dir: string): CodegenStore => {
|
|
|
72
56
|
runtimeVersion: store.gi.version,
|
|
73
57
|
react:
|
|
74
58
|
hasReactRuntime && store.jsx !== null
|
|
75
|
-
? { version: store.jsx.version
|
|
59
|
+
? { version: store.jsx.version }
|
|
76
60
|
: null,
|
|
77
61
|
};
|
|
78
62
|
};
|
package/src/commands/docs.ts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ElementProps,
|
|
3
|
-
mergeOmittedProps,
|
|
4
|
-
type OmittedProps,
|
|
5
|
-
readBuiltinElements,
|
|
6
|
-
resolveGirPath,
|
|
7
|
-
resolveLibraries,
|
|
8
|
-
resolveStore,
|
|
9
|
-
} from "@gtkx/codegen";
|
|
1
|
+
import { mergeOmittedProps, resolveGirPath, resolveLibraries } from "@gtkx/codegen";
|
|
10
2
|
import { writeDocs } from "@gtkx/codegen/internal";
|
|
11
3
|
import { loadConfig } from "@gtkx/config";
|
|
12
4
|
import { resolveOmittedProps } from "@gtkx/config/internal";
|
|
13
|
-
import { info } from "@gtkx/utils";
|
|
5
|
+
import { info, isPathInside } from "@gtkx/utils";
|
|
14
6
|
import { defineCommand } from "citty";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
7
|
+
import { resolve } from "node:path";
|
|
8
|
+
import { resolveDocsElements } from "../internal/docs-elements.js";
|
|
17
9
|
import { cwdArg, resolveCwd } from "../internal/entry-arg.js";
|
|
18
10
|
|
|
19
11
|
const docs = defineCommand({
|
|
@@ -65,7 +57,7 @@ const docs = defineCommand({
|
|
|
65
57
|
);
|
|
66
58
|
}
|
|
67
59
|
|
|
68
|
-
const libraries = resolveLibraries(config.libraries
|
|
60
|
+
const libraries = resolveLibraries(config.libraries);
|
|
69
61
|
const startedAt = Date.now();
|
|
70
62
|
const outDir = resolveOutDir(cwd, args.out);
|
|
71
63
|
const builtin = await resolveDocsElements(cwd);
|
|
@@ -78,10 +70,6 @@ const docs = defineCommand({
|
|
|
78
70
|
props: builtin.props,
|
|
79
71
|
omittedProps: mergeOmittedProps(builtin.omittedProps, resolveOmittedProps(config.elements)),
|
|
80
72
|
isForced: args.force,
|
|
81
|
-
isByteArrayTyped: config.future?.v2ByteArrays === true,
|
|
82
|
-
isValueUnwrapped: config.future?.v2ValueReturns === true,
|
|
83
|
-
isFinishTrimmed: config.future?.v2FinishResults === true,
|
|
84
|
-
isInoutInPlace: config.future?.v2InoutReturns === true,
|
|
85
73
|
});
|
|
86
74
|
|
|
87
75
|
if (!isRegenerated) {
|
|
@@ -99,12 +87,6 @@ const docs = defineCommand({
|
|
|
99
87
|
},
|
|
100
88
|
});
|
|
101
89
|
|
|
102
|
-
const isBelow = (parent: string, child: string): boolean => {
|
|
103
|
-
const path = relative(parent, child);
|
|
104
|
-
|
|
105
|
-
return path !== "" && path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute(path);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
90
|
const outDirReason = (cwd: string, out: string, outDir: string): string => {
|
|
109
91
|
if (out.trim() === "") {
|
|
110
92
|
return "it was empty, which names the project root itself";
|
|
@@ -120,7 +102,7 @@ const outDirReason = (cwd: string, out: string, outDir: string): string => {
|
|
|
120
102
|
const resolveOutDir = (cwd: string, out: string): string => {
|
|
121
103
|
const outDir = out.trim() === "" ? cwd : resolve(cwd, out);
|
|
122
104
|
|
|
123
|
-
if (
|
|
105
|
+
if (isPathInside(cwd, outDir)) {
|
|
124
106
|
return outDir;
|
|
125
107
|
}
|
|
126
108
|
|
|
@@ -130,16 +112,4 @@ const resolveOutDir = (cwd: string, out: string): string => {
|
|
|
130
112
|
);
|
|
131
113
|
};
|
|
132
114
|
|
|
133
|
-
const resolveDocsElements = async (cwd: string): Promise<{ props: ElementProps; omittedProps: OmittedProps }> => {
|
|
134
|
-
const { gi, reactSubexports } = resolveStore(cwd);
|
|
135
|
-
|
|
136
|
-
if (!existsSync(gi.storeDir)) {
|
|
137
|
-
return { props: {}, omittedProps: {} };
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const { props, omittedProps } = await readBuiltinElements(reactSubexports, gi.storeDir);
|
|
141
|
-
|
|
142
|
-
return { props, omittedProps };
|
|
143
|
-
};
|
|
144
|
-
|
|
145
115
|
export { docs };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { info } from "@gtkx/utils";
|
|
2
|
+
import { defineCommand } from "citty";
|
|
3
|
+
import { cwdArg, resolveCwd } from "../internal/entry-arg.js";
|
|
4
|
+
import { type ClientName, type ClientResult, CLIENTS, isClientName, writeClientConfig } from "../mcp/client-config.js";
|
|
5
|
+
|
|
6
|
+
const clientList = CLIENTS.map((client) => client.name).join(", ");
|
|
7
|
+
|
|
8
|
+
const init = defineCommand({
|
|
9
|
+
meta: {
|
|
10
|
+
name: "init",
|
|
11
|
+
description: "Write the gtkx MCP server into an editor's configuration file",
|
|
12
|
+
},
|
|
13
|
+
args: {
|
|
14
|
+
client: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: `Which editor to configure: one of ${clientList}`,
|
|
17
|
+
required: true,
|
|
18
|
+
},
|
|
19
|
+
...cwdArg,
|
|
20
|
+
},
|
|
21
|
+
run({ args }) {
|
|
22
|
+
const cwd = resolveCwd(args);
|
|
23
|
+
const name = args.client;
|
|
24
|
+
|
|
25
|
+
if (!isClientName(name)) {
|
|
26
|
+
throw new Error(`Unknown --client "${name}". Pass one of ${clientList}.`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
report(name, writeClientConfig(cwd, name));
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const mcp = defineCommand({
|
|
34
|
+
meta: {
|
|
35
|
+
name: "mcp",
|
|
36
|
+
description: "Run the MCP server that exposes this project's running app and generated API reference",
|
|
37
|
+
},
|
|
38
|
+
args: {
|
|
39
|
+
tools: {
|
|
40
|
+
type: "string",
|
|
41
|
+
description:
|
|
42
|
+
"Comma-separated tool name patterns to register, `*` matching any run of characters and a " +
|
|
43
|
+
"leading `!` excluding. Overrides `mcp.tools` in gtkx.config.ts",
|
|
44
|
+
},
|
|
45
|
+
"read-only": {
|
|
46
|
+
type: "boolean",
|
|
47
|
+
description: "Register only the tools that read state, leaving out the ones that drive the app",
|
|
48
|
+
},
|
|
49
|
+
...cwdArg,
|
|
50
|
+
},
|
|
51
|
+
subCommands: { init },
|
|
52
|
+
async run({ args }) {
|
|
53
|
+
const { runMcpServer } = await import("@gtkx/mcp/server");
|
|
54
|
+
|
|
55
|
+
await runMcpServer({
|
|
56
|
+
cwd: resolveCwd(args),
|
|
57
|
+
...(args.tools !== undefined && { tools: splitPatterns(args.tools) }),
|
|
58
|
+
...(args["read-only"] !== undefined && { isReadOnly: args["read-only"] }),
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const splitPatterns = (value: string): string[] =>
|
|
64
|
+
value.split(",").map((pattern) => pattern.trim()).filter((pattern) => pattern.length > 0);
|
|
65
|
+
|
|
66
|
+
const report = (name: ClientName, result: ClientResult): void => {
|
|
67
|
+
if (result.kind === "manual") {
|
|
68
|
+
info(`mcp: ${name} keeps its servers in ${result.path}, which is outside this project. Add:`);
|
|
69
|
+
|
|
70
|
+
for (const line of result.snippet.split("\n")) {
|
|
71
|
+
info(`mcp: ${line}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
info(`mcp: ${result.isCreated ? "created" : "updated"} ${result.path} for ${name}`);
|
|
78
|
+
info("mcp: restart the editor for it to pick the server up");
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export { mcp };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import type { DeploySettings, Notice, NoticeSection } from "../types.js";
|
|
3
2
|
import { BUNDLE_FILENAME } from "../../vite-plugins/esm-extension.js";
|
|
3
|
+
import { readLicenseText } from "../notices/text.js";
|
|
4
4
|
|
|
5
5
|
type FileStanza = {
|
|
6
6
|
settings: DeploySettings;
|
|
@@ -30,18 +30,6 @@ const foldedField = (name: string, lines: string[]): string[] => {
|
|
|
30
30
|
return first === undefined ? [] : [`${name}: ${first}`, ...rest.map((line) => indentLine(line))];
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
const licenseText = (licenseFile: string | null): string | null => {
|
|
34
|
-
if (licenseFile === null) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
return readFileSync(licenseFile, "utf8").trimEnd();
|
|
40
|
-
} catch {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
33
|
const shortName = (license: string): string =>
|
|
46
34
|
license
|
|
47
35
|
.replaceAll(SPDX_GROUPING, " ")
|
|
@@ -159,7 +147,7 @@ const applicationStanza = (settings: DeploySettings, text: string | null): strin
|
|
|
159
147
|
];
|
|
160
148
|
|
|
161
149
|
const renderCopyright = (settings: DeploySettings, sections: NoticeSection[]): string => {
|
|
162
|
-
const own =
|
|
150
|
+
const own = settings.paths.licenseFile === null ? null : readLicenseText(settings.paths.licenseFile);
|
|
163
151
|
const reproduced: Set<string> = new Set(own === null ? [] : [own]);
|
|
164
152
|
|
|
165
153
|
const stanzas = filePatterns(sections).flatMap((files) =>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import XMLBuilder from "fast-xml-builder";
|
|
2
|
+
|
|
1
3
|
type XmlNode = {
|
|
2
4
|
tag: string;
|
|
3
5
|
attributes?: Record<string, string>;
|
|
@@ -5,23 +7,26 @@ type XmlNode = {
|
|
|
5
7
|
text?: string;
|
|
6
8
|
};
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
const INDENT = " ".repeat(4);
|
|
10
|
+
type OrderedNode = Record<string, unknown>;
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
-
'"': """,
|
|
13
|
-
"&": "&",
|
|
14
|
-
"<": "<",
|
|
15
|
-
">": ">",
|
|
16
|
-
};
|
|
12
|
+
const XML_ENCODING = ["UTF", "8"].join("-");
|
|
17
13
|
|
|
18
|
-
const
|
|
19
|
-
|
|
14
|
+
const builder = new XMLBuilder({
|
|
15
|
+
format: true,
|
|
16
|
+
ignoreAttributes: false,
|
|
17
|
+
indentBy: " ".repeat(4),
|
|
18
|
+
preserveOrder: true,
|
|
19
|
+
suppressEmptyNode: true,
|
|
20
|
+
});
|
|
20
21
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
.map((
|
|
24
|
-
|
|
22
|
+
const orderedNode = (node: XmlNode): OrderedNode => ({
|
|
23
|
+
[node.tag]: node.text === undefined
|
|
24
|
+
? (node.children ?? []).map((child) => orderedNode(child))
|
|
25
|
+
: [{ "#text": node.text }],
|
|
26
|
+
...(node.attributes && {
|
|
27
|
+
":@": Object.fromEntries(Object.entries(node.attributes).map(([key, value]) => [`@_${key}`, value])),
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
25
30
|
|
|
26
31
|
const element = (tag: string, attributes: Record<string, string>, children: XmlNode[]): XmlNode => ({
|
|
27
32
|
tag,
|
|
@@ -31,23 +36,10 @@ const element = (tag: string, attributes: Record<string, string>, children: XmlN
|
|
|
31
36
|
|
|
32
37
|
const text = (tag: string, value: string): XmlNode => ({ tag, text: value });
|
|
33
38
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return [`${open}>${escapeXml(node.text)}</${node.tag}>`];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const children = node.children ?? [];
|
|
43
|
-
|
|
44
|
-
if (children.length === 0) {
|
|
45
|
-
return [`${open}/>`];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return [`${open}>`, ...children.flatMap((child) => renderNode(child, depth + 1)), `${padding}</${node.tag}>`];
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const renderDocument = (root: XmlNode): string => [XML_DECLARATION, ...renderNode(root, 0), ""].join("\n");
|
|
39
|
+
const renderDocument = (root: XmlNode): string =>
|
|
40
|
+
`${builder.build([
|
|
41
|
+
{ "?xml": [{ "#text": "" }], ":@": { "@_version": "1.0", "@_encoding": XML_ENCODING } },
|
|
42
|
+
orderedNode(root),
|
|
43
|
+
])}\n`;
|
|
52
44
|
|
|
53
45
|
export { element, renderDocument, text, type XmlNode };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { dirname, join } from "node:path";
|
|
2
|
+
import { readLicenseText } from "../notices/text.js";
|
|
3
3
|
|
|
4
4
|
const LICENSE_FILENAME = "LICENSE";
|
|
5
5
|
const NODE_MARKER = "Node.js";
|
|
@@ -10,13 +10,7 @@ const licenseCandidates = (binary: string): string[] => {
|
|
|
10
10
|
return [join(dir, LICENSE_FILENAME), join(dir, "..", LICENSE_FILENAME)];
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
const isNodeLicense = (path: string): boolean =>
|
|
14
|
-
try {
|
|
15
|
-
return readFileSync(path, "utf8").includes(NODE_MARKER);
|
|
16
|
-
} catch {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
};
|
|
13
|
+
const isNodeLicense = (path: string): boolean => readLicenseText(path)?.includes(NODE_MARKER) === true;
|
|
20
14
|
|
|
21
15
|
const licenseBesideNode = (binary: string): string | null =>
|
|
22
16
|
licenseCandidates(binary).find((candidate) => isNodeLicense(candidate)) ?? null;
|
|
@@ -44,7 +44,7 @@ const summaryFor = (settings: DeploySettings, packages: BundledPackage[]): strin
|
|
|
44
44
|
"Section 3.2(a) asks that whoever receives an executable form be told how to obtain the source code,",
|
|
45
45
|
"which is what the source pointer below is for: it leads to the release these files were built from.",
|
|
46
46
|
`The addon also statically links Rust crates GTKX did not write, so ${lib}/${NATIVE_FILENAME} is not`,
|
|
47
|
-
`${LICENSE_NAME} alone. The
|
|
47
|
+
`${LICENSE_NAME} alone. The crates notice below names the licenses those crates carry; it does not`,
|
|
48
48
|
`reproduce their texts, and ${CRATES_MANIFEST} in the source pointed at records which crates went in`,
|
|
49
49
|
"and at which versions.",
|
|
50
50
|
...modulesLine(packages),
|
|
@@ -36,7 +36,8 @@ const SUMMARY = [
|
|
|
36
36
|
"their own terms; this package does not distribute them at all.",
|
|
37
37
|
"The GTKX native addon does link GLib, GObject and GIO dynamically against the copies already installed",
|
|
38
38
|
"on the system, which makes the addon a work that uses those libraries, and section 6 of the LGPL asks",
|
|
39
|
-
"such a work to carry
|
|
39
|
+
"such a work to carry a notice, the license, and the copyright notices. This is the notice it asks for,",
|
|
40
|
+
"and the license itself is published at",
|
|
40
41
|
`${LGPL_URL},`,
|
|
41
42
|
"and the copyright notice of each library is published with its sources, at the address listed beside",
|
|
42
43
|
"it below. Linking against an installed shared library is the mechanism section 6(b) allows, so the",
|