flowdular 0.3.2 → 0.4.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/dist/distribution.js +370 -5
- package/dist/index.js +646 -41
- package/package.json +2 -2
package/dist/distribution.js
CHANGED
|
@@ -2478,6 +2478,17 @@ var module_spec_schema_default = {
|
|
|
2478
2478
|
type: "array",
|
|
2479
2479
|
items: { $ref: "#/$defs/decision" },
|
|
2480
2480
|
uniqueItems: true
|
|
2481
|
+
},
|
|
2482
|
+
research: { $ref: "#/$defs/research" },
|
|
2483
|
+
adapters: {
|
|
2484
|
+
type: "array",
|
|
2485
|
+
items: { $ref: "#/$defs/adapter" },
|
|
2486
|
+
uniqueItems: true
|
|
2487
|
+
},
|
|
2488
|
+
templates: {
|
|
2489
|
+
type: "array",
|
|
2490
|
+
items: { $ref: "#/$defs/template" },
|
|
2491
|
+
uniqueItems: true
|
|
2481
2492
|
}
|
|
2482
2493
|
},
|
|
2483
2494
|
allOf: [
|
|
@@ -2495,7 +2506,10 @@ var module_spec_schema_default = {
|
|
|
2495
2506
|
settings: false,
|
|
2496
2507
|
agentTools: false,
|
|
2497
2508
|
outOfScope: false,
|
|
2498
|
-
decisions: false
|
|
2509
|
+
decisions: false,
|
|
2510
|
+
research: false,
|
|
2511
|
+
adapters: false,
|
|
2512
|
+
templates: false
|
|
2499
2513
|
}
|
|
2500
2514
|
}
|
|
2501
2515
|
}
|
|
@@ -2701,6 +2715,113 @@ var module_spec_schema_default = {
|
|
|
2701
2715
|
answer: { type: "string", minLength: 1 },
|
|
2702
2716
|
decidedBy: { enum: ["user", "default"] }
|
|
2703
2717
|
}
|
|
2718
|
+
},
|
|
2719
|
+
domain: {
|
|
2720
|
+
type: "string",
|
|
2721
|
+
maxLength: 253,
|
|
2722
|
+
pattern: "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$"
|
|
2723
|
+
},
|
|
2724
|
+
research: {
|
|
2725
|
+
type: "object",
|
|
2726
|
+
additionalProperties: false,
|
|
2727
|
+
required: ["adapter", "evidenceOwner"],
|
|
2728
|
+
properties: {
|
|
2729
|
+
adapter: {
|
|
2730
|
+
enum: [
|
|
2731
|
+
"model-native",
|
|
2732
|
+
"searxng",
|
|
2733
|
+
"firecrawl",
|
|
2734
|
+
"connector",
|
|
2735
|
+
"recorded"
|
|
2736
|
+
]
|
|
2737
|
+
},
|
|
2738
|
+
allowDomains: {
|
|
2739
|
+
type: "array",
|
|
2740
|
+
items: { $ref: "#/$defs/domain" },
|
|
2741
|
+
uniqueItems: true
|
|
2742
|
+
},
|
|
2743
|
+
denyDomains: {
|
|
2744
|
+
type: "array",
|
|
2745
|
+
items: { $ref: "#/$defs/domain" },
|
|
2746
|
+
uniqueItems: true
|
|
2747
|
+
},
|
|
2748
|
+
monthlyQueryBudget: { type: "integer", minimum: 1 },
|
|
2749
|
+
evidenceOwner: { $ref: "#/$defs/entityId" }
|
|
2750
|
+
}
|
|
2751
|
+
},
|
|
2752
|
+
adapter: {
|
|
2753
|
+
type: "object",
|
|
2754
|
+
additionalProperties: false,
|
|
2755
|
+
required: [
|
|
2756
|
+
"id",
|
|
2757
|
+
"direction",
|
|
2758
|
+
"connector",
|
|
2759
|
+
"operation",
|
|
2760
|
+
"port",
|
|
2761
|
+
"mapping"
|
|
2762
|
+
],
|
|
2763
|
+
properties: {
|
|
2764
|
+
id: {
|
|
2765
|
+
type: "string",
|
|
2766
|
+
pattern: "^[a-z][a-z0-9-]*(\\.[a-z][a-z0-9-]*)+$"
|
|
2767
|
+
},
|
|
2768
|
+
direction: { enum: ["source", "sink"] },
|
|
2769
|
+
connector: { type: "string", pattern: "^[a-z][a-z0-9-]{0,95}$" },
|
|
2770
|
+
operation: { type: "string", pattern: "^[a-z][a-z0-9-]{0,63}$" },
|
|
2771
|
+
port: {
|
|
2772
|
+
type: "string",
|
|
2773
|
+
maxLength: 96,
|
|
2774
|
+
pattern: "^[a-z][a-z0-9-]*(\\.[a-z][a-z0-9-]*)+$"
|
|
2775
|
+
},
|
|
2776
|
+
schedule: {
|
|
2777
|
+
anyOf: [
|
|
2778
|
+
{ type: "null" },
|
|
2779
|
+
{
|
|
2780
|
+
type: "string",
|
|
2781
|
+
maxLength: 100,
|
|
2782
|
+
pattern: "^[0-9a-z*,/-]+( [0-9a-z*,/-]+){4}$"
|
|
2783
|
+
}
|
|
2784
|
+
]
|
|
2785
|
+
},
|
|
2786
|
+
mapping: {
|
|
2787
|
+
type: "array",
|
|
2788
|
+
minItems: 1,
|
|
2789
|
+
items: { $ref: "#/$defs/adapterMapping" },
|
|
2790
|
+
uniqueItems: true
|
|
2791
|
+
},
|
|
2792
|
+
recorded: {
|
|
2793
|
+
type: "string",
|
|
2794
|
+
pattern: "^adapters/[a-z0-9][a-z0-9-]*\\.recorded\\.json$"
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2797
|
+
},
|
|
2798
|
+
adapterMapping: {
|
|
2799
|
+
type: "object",
|
|
2800
|
+
additionalProperties: false,
|
|
2801
|
+
required: ["to", "transform"],
|
|
2802
|
+
properties: {
|
|
2803
|
+
from: { type: "string", minLength: 1 },
|
|
2804
|
+
to: { type: "string", minLength: 1 },
|
|
2805
|
+
transform: { enum: ["rename", "constant", "format", "lookup"] },
|
|
2806
|
+
value: {
|
|
2807
|
+
anyOf: [{ type: "null" }, { type: "string", minLength: 1 }]
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
},
|
|
2811
|
+
template: {
|
|
2812
|
+
type: "object",
|
|
2813
|
+
additionalProperties: false,
|
|
2814
|
+
required: ["id", "title", "inputEntity", "format", "body"],
|
|
2815
|
+
properties: {
|
|
2816
|
+
id: { $ref: "#/$defs/entityId" },
|
|
2817
|
+
title: { type: "string", minLength: 1 },
|
|
2818
|
+
inputEntity: { $ref: "#/$defs/entityId" },
|
|
2819
|
+
format: { enum: ["pdf", "docx"] },
|
|
2820
|
+
body: {
|
|
2821
|
+
type: "string",
|
|
2822
|
+
pattern: "^templates/[a-z][a-z0-9-]*\\.md$"
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2704
2825
|
}
|
|
2705
2826
|
}
|
|
2706
2827
|
};
|
|
@@ -2867,6 +2988,15 @@ var project_schema_default = {
|
|
|
2867
2988
|
$ref: "#/$defs/githubAccount"
|
|
2868
2989
|
},
|
|
2869
2990
|
uniqueItems: true
|
|
2991
|
+
},
|
|
2992
|
+
labels: {
|
|
2993
|
+
type: "array",
|
|
2994
|
+
maxItems: 10,
|
|
2995
|
+
items: {
|
|
2996
|
+
type: "string",
|
|
2997
|
+
pattern: "^[A-Za-z0-9][A-Za-z0-9 ._:-]{0,49}$"
|
|
2998
|
+
},
|
|
2999
|
+
uniqueItems: true
|
|
2870
3000
|
}
|
|
2871
3001
|
}
|
|
2872
3002
|
},
|
|
@@ -3114,8 +3244,79 @@ var projectSchema = project_schema_default;
|
|
|
3114
3244
|
var moduleCatalogSchema = module_catalog_schema_default;
|
|
3115
3245
|
var moduleArtifactSchema = module_artifact_schema_default;
|
|
3116
3246
|
|
|
3247
|
+
// ../contracts/src/translations.ts
|
|
3248
|
+
var PLURAL_CATEGORIES = [
|
|
3249
|
+
"zero",
|
|
3250
|
+
"one",
|
|
3251
|
+
"two",
|
|
3252
|
+
"few",
|
|
3253
|
+
"many",
|
|
3254
|
+
"other"
|
|
3255
|
+
];
|
|
3256
|
+
var WHOLE_NUMBER_SAMPLES = [
|
|
3257
|
+
...Array.from({ length: 200 }, (_, index) => index),
|
|
3258
|
+
1e3,
|
|
3259
|
+
1e4,
|
|
3260
|
+
1e5,
|
|
3261
|
+
1e6,
|
|
3262
|
+
1e7,
|
|
3263
|
+
1e8,
|
|
3264
|
+
1e9
|
|
3265
|
+
];
|
|
3266
|
+
function requiredPluralCategories(locale) {
|
|
3267
|
+
const rules = new Intl.PluralRules(locale);
|
|
3268
|
+
const selected = /* @__PURE__ */ new Set(["other"]);
|
|
3269
|
+
for (const sample of WHOLE_NUMBER_SAMPLES) selected.add(rules.select(sample));
|
|
3270
|
+
return PLURAL_CATEGORIES.filter((category) => selected.has(category));
|
|
3271
|
+
}
|
|
3272
|
+
function pluralMember(bundle, key) {
|
|
3273
|
+
const dot = key.lastIndexOf(".");
|
|
3274
|
+
if (dot <= 0) return null;
|
|
3275
|
+
const category = key.slice(dot + 1);
|
|
3276
|
+
if (!PLURAL_CATEGORIES.includes(category)) return null;
|
|
3277
|
+
const base = key.slice(0, dot);
|
|
3278
|
+
return Object.hasOwn(bundle, base + ".other") ? { base, category } : null;
|
|
3279
|
+
}
|
|
3280
|
+
function translationKeys(bundle) {
|
|
3281
|
+
const keys = /* @__PURE__ */ new Set();
|
|
3282
|
+
for (const key of Object.keys(bundle)) {
|
|
3283
|
+
keys.add(pluralMember(bundle, key)?.base ?? key);
|
|
3284
|
+
}
|
|
3285
|
+
return [...keys].sort();
|
|
3286
|
+
}
|
|
3287
|
+
function pluralFamilyIssues(bundle, locale) {
|
|
3288
|
+
const families = /* @__PURE__ */ new Map();
|
|
3289
|
+
for (const key of Object.keys(bundle)) {
|
|
3290
|
+
const member = pluralMember(bundle, key);
|
|
3291
|
+
if (member === null) continue;
|
|
3292
|
+
const categories = families.get(member.base) ?? /* @__PURE__ */ new Set();
|
|
3293
|
+
categories.add(member.category);
|
|
3294
|
+
families.set(member.base, categories);
|
|
3295
|
+
}
|
|
3296
|
+
const required = requiredPluralCategories(locale);
|
|
3297
|
+
const known = new Intl.PluralRules(
|
|
3298
|
+
locale
|
|
3299
|
+
).resolvedOptions().pluralCategories;
|
|
3300
|
+
const issues = [];
|
|
3301
|
+
for (const base of [...families.keys()].sort()) {
|
|
3302
|
+
const categories = families.get(base);
|
|
3303
|
+
const missing = required.filter((category) => !categories.has(category));
|
|
3304
|
+
if (missing.length > 0) {
|
|
3305
|
+
issues.push(
|
|
3306
|
+
`${base} lacks ${missing.map((category) => base + "." + category).join(", ")} for ${locale}`
|
|
3307
|
+
);
|
|
3308
|
+
}
|
|
3309
|
+
for (const category of categories) {
|
|
3310
|
+
if (!known.includes(category)) {
|
|
3311
|
+
issues.push(`${base}.${category} is never selected for ${locale}`);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
return issues;
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3117
3318
|
// ../contracts/src/index.ts
|
|
3118
|
-
var PLATFORM_API_VERSION = "0.1.
|
|
3319
|
+
var PLATFORM_API_VERSION = "0.1.21";
|
|
3119
3320
|
|
|
3120
3321
|
// ../kernel/src/module-compatibility.ts
|
|
3121
3322
|
function satisfiesModuleVersion(version, range) {
|
|
@@ -3298,6 +3499,10 @@ var validators = {
|
|
|
3298
3499
|
cliExtension: ajv.compile(cliExtensionSchema),
|
|
3299
3500
|
platformSpec: ajv.compile(platformSpecSchema)
|
|
3300
3501
|
};
|
|
3502
|
+
var MONTH_NAMES = "jan feb mar apr may jun jul aug sep oct nov dec".split(
|
|
3503
|
+
" "
|
|
3504
|
+
);
|
|
3505
|
+
var WEEKDAY_NAMES = "sun mon tue wed thu fri sat".split(" ");
|
|
3301
3506
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
3302
3507
|
".git",
|
|
3303
3508
|
".flowdular",
|
|
@@ -3796,7 +4001,7 @@ import { dirname as dirname6, join as join6, relative as relative5 } from "node:
|
|
|
3796
4001
|
import { createRequire } from "node:module";
|
|
3797
4002
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
3798
4003
|
import { dirname as dirname4, join as join3 } from "node:path";
|
|
3799
|
-
var SDK_VERSION = "0.
|
|
4004
|
+
var SDK_VERSION = "0.4.0";
|
|
3800
4005
|
function npmPackage(specifier) {
|
|
3801
4006
|
return specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
|
|
3802
4007
|
}
|
|
@@ -3900,6 +4105,115 @@ async function findModuleFiles(workspace) {
|
|
|
3900
4105
|
import { access as access2, readFile as readFile7, readdir as readdir3 } from "node:fs/promises";
|
|
3901
4106
|
import { dirname as dirname5, join as join5, relative as relative4 } from "node:path";
|
|
3902
4107
|
import { parse as parseYaml3 } from "yaml";
|
|
4108
|
+
|
|
4109
|
+
// src/dom-properties.ts
|
|
4110
|
+
var DOM_PROPERTY_SPELLINGS = [
|
|
4111
|
+
"acceptCharset",
|
|
4112
|
+
"allowFullScreen",
|
|
4113
|
+
"autoCapitalize",
|
|
4114
|
+
"autoComplete",
|
|
4115
|
+
"autoCorrect",
|
|
4116
|
+
"autoFocus",
|
|
4117
|
+
"autoPlay",
|
|
4118
|
+
"charSet",
|
|
4119
|
+
"contentEditable",
|
|
4120
|
+
"crossOrigin",
|
|
4121
|
+
"defaultChecked",
|
|
4122
|
+
"defaultValue",
|
|
4123
|
+
"disablePictureInPicture",
|
|
4124
|
+
"disableRemotePlayback",
|
|
4125
|
+
"encType",
|
|
4126
|
+
"fetchPriority",
|
|
4127
|
+
"formAction",
|
|
4128
|
+
"formEncType",
|
|
4129
|
+
"formMethod",
|
|
4130
|
+
"formNoValidate",
|
|
4131
|
+
"formTarget",
|
|
4132
|
+
"httpEquiv",
|
|
4133
|
+
"imageSizes",
|
|
4134
|
+
"imageSrcSet",
|
|
4135
|
+
"inputMode",
|
|
4136
|
+
"itemID",
|
|
4137
|
+
"itemProp",
|
|
4138
|
+
"itemRef",
|
|
4139
|
+
"itemScope",
|
|
4140
|
+
"itemType",
|
|
4141
|
+
"maxLength",
|
|
4142
|
+
"noModule",
|
|
4143
|
+
"noValidate",
|
|
4144
|
+
"playsInline",
|
|
4145
|
+
"readOnly",
|
|
4146
|
+
"referrerPolicy",
|
|
4147
|
+
"spellCheck",
|
|
4148
|
+
"srcDoc",
|
|
4149
|
+
"srcLang",
|
|
4150
|
+
"srcSet",
|
|
4151
|
+
"tabIndex",
|
|
4152
|
+
"viewBox"
|
|
4153
|
+
];
|
|
4154
|
+
var SPELLINGS = new Map(
|
|
4155
|
+
DOM_PROPERTY_SPELLINGS.map((name) => [name.toLowerCase(), name])
|
|
4156
|
+
);
|
|
4157
|
+
function hostTagAttributes(source) {
|
|
4158
|
+
const tags = [];
|
|
4159
|
+
for (const match of source.matchAll(/<[a-z][a-z0-9-]*/g)) {
|
|
4160
|
+
const start = match.index + match[0].length;
|
|
4161
|
+
let depth = 0;
|
|
4162
|
+
let quote = "";
|
|
4163
|
+
let text = "";
|
|
4164
|
+
let end = start;
|
|
4165
|
+
for (; end < source.length; end += 1) {
|
|
4166
|
+
const character = source[end];
|
|
4167
|
+
if (quote !== "") {
|
|
4168
|
+
if (character === quote) quote = "";
|
|
4169
|
+
text += " ";
|
|
4170
|
+
continue;
|
|
4171
|
+
}
|
|
4172
|
+
if (depth > 0) {
|
|
4173
|
+
if (character === "{") depth += 1;
|
|
4174
|
+
else if (character === "}") depth -= 1;
|
|
4175
|
+
text += depth === 0 ? character : " ";
|
|
4176
|
+
continue;
|
|
4177
|
+
}
|
|
4178
|
+
if (character === "{") {
|
|
4179
|
+
depth = 1;
|
|
4180
|
+
text += character;
|
|
4181
|
+
continue;
|
|
4182
|
+
}
|
|
4183
|
+
if (character === '"' || character === "'") {
|
|
4184
|
+
quote = character;
|
|
4185
|
+
text += character;
|
|
4186
|
+
continue;
|
|
4187
|
+
}
|
|
4188
|
+
if (character === ">") break;
|
|
4189
|
+
text += character;
|
|
4190
|
+
}
|
|
4191
|
+
tags.push({ start, text });
|
|
4192
|
+
}
|
|
4193
|
+
return tags;
|
|
4194
|
+
}
|
|
4195
|
+
function domPropertyMisspellings(source) {
|
|
4196
|
+
const found = [];
|
|
4197
|
+
for (const tag of hostTagAttributes(source)) {
|
|
4198
|
+
for (const attribute of tag.text.matchAll(
|
|
4199
|
+
/(?<=\s)([A-Za-z][A-Za-z-]*)=/g
|
|
4200
|
+
)) {
|
|
4201
|
+
const name = attribute[1];
|
|
4202
|
+
const expected = SPELLINGS.get(name.toLowerCase());
|
|
4203
|
+
if (expected === void 0 || expected === name) continue;
|
|
4204
|
+
const index = tag.start + attribute.index;
|
|
4205
|
+
found.push({
|
|
4206
|
+
name,
|
|
4207
|
+
expected,
|
|
4208
|
+
index,
|
|
4209
|
+
line: source.slice(0, index).split("\n").length
|
|
4210
|
+
});
|
|
4211
|
+
}
|
|
4212
|
+
}
|
|
4213
|
+
return found.sort((left, right) => left.index - right.index);
|
|
4214
|
+
}
|
|
4215
|
+
|
|
4216
|
+
// src/module-validate.ts
|
|
3903
4217
|
function issue(code, message, path, severity = "error") {
|
|
3904
4218
|
return { code, message, path, severity };
|
|
3905
4219
|
}
|
|
@@ -4088,6 +4402,7 @@ async function translationIssues(moduleRoot, manifest, projectLocales) {
|
|
|
4088
4402
|
}
|
|
4089
4403
|
if (!manifest.capabilities.includes("translations")) return issues;
|
|
4090
4404
|
const keySets = /* @__PURE__ */ new Map();
|
|
4405
|
+
const referenceBundleKeys = /* @__PURE__ */ new Set();
|
|
4091
4406
|
for (const locale of manifest.locales) {
|
|
4092
4407
|
const path = `translations/${locale}.json`;
|
|
4093
4408
|
if (!await exists(join5(moduleRoot, path))) {
|
|
@@ -4105,7 +4420,21 @@ async function translationIssues(moduleRoot, manifest, projectLocales) {
|
|
|
4105
4420
|
if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) {
|
|
4106
4421
|
throw new Error("Expected a JSON object.");
|
|
4107
4422
|
}
|
|
4108
|
-
|
|
4423
|
+
const strings = bundle;
|
|
4424
|
+
keySets.set(locale, translationKeys(strings));
|
|
4425
|
+
if (keySets.size === 1) {
|
|
4426
|
+
for (const key of Object.keys(strings)) referenceBundleKeys.add(key);
|
|
4427
|
+
}
|
|
4428
|
+
const plurals = pluralFamilyIssues(strings, locale);
|
|
4429
|
+
if (plurals.length > 0) {
|
|
4430
|
+
issues.push(
|
|
4431
|
+
issue(
|
|
4432
|
+
"TRANSLATION_PLURAL_INCOMPLETE",
|
|
4433
|
+
`${path} plural families do not match the ${locale} plural rules: ${plurals.join("; ")}.`,
|
|
4434
|
+
path
|
|
4435
|
+
)
|
|
4436
|
+
);
|
|
4437
|
+
}
|
|
4109
4438
|
} catch (error) {
|
|
4110
4439
|
issues.push(
|
|
4111
4440
|
issue(
|
|
@@ -4134,7 +4463,7 @@ async function translationIssues(moduleRoot, manifest, projectLocales) {
|
|
|
4134
4463
|
)
|
|
4135
4464
|
);
|
|
4136
4465
|
}
|
|
4137
|
-
const referenceKeys = new Set(reference[1]);
|
|
4466
|
+
const referenceKeys = /* @__PURE__ */ new Set([...reference[1], ...referenceBundleKeys]);
|
|
4138
4467
|
const files = await clientSourceFiles(moduleRoot);
|
|
4139
4468
|
if (files.length > 0) {
|
|
4140
4469
|
const namespace = manifest.id.split(".")[0] ?? manifest.id;
|
|
@@ -4166,6 +4495,21 @@ async function translationIssues(moduleRoot, manifest, projectLocales) {
|
|
|
4166
4495
|
}
|
|
4167
4496
|
return issues;
|
|
4168
4497
|
}
|
|
4498
|
+
function filtersTags(source) {
|
|
4499
|
+
const tags = [];
|
|
4500
|
+
for (const match of source.matchAll(/<Filters\b/g)) {
|
|
4501
|
+
let depth = 0;
|
|
4502
|
+
let end = match.index + match[0].length;
|
|
4503
|
+
for (; end < source.length; end += 1) {
|
|
4504
|
+
const character = source[end];
|
|
4505
|
+
if (character === "{") depth += 1;
|
|
4506
|
+
else if (character === "}") depth -= 1;
|
|
4507
|
+
else if (character === ">" && depth === 0) break;
|
|
4508
|
+
}
|
|
4509
|
+
tags.push(source.slice(match.index, end));
|
|
4510
|
+
}
|
|
4511
|
+
return tags;
|
|
4512
|
+
}
|
|
4169
4513
|
async function userInterfaceIssues(moduleRoot) {
|
|
4170
4514
|
const issues = [];
|
|
4171
4515
|
for (const file of await clientSourceFiles(moduleRoot)) {
|
|
@@ -4189,6 +4533,27 @@ async function userInterfaceIssues(moduleRoot) {
|
|
|
4189
4533
|
)
|
|
4190
4534
|
);
|
|
4191
4535
|
}
|
|
4536
|
+
const misspelled = domPropertyMisspellings(source);
|
|
4537
|
+
if (misspelled.length > 0) {
|
|
4538
|
+
issues.push(
|
|
4539
|
+
issue(
|
|
4540
|
+
"DOM_PROPERTY_CASING",
|
|
4541
|
+
"Host elements use Octane's DOM property spelling: " + misspelled.map(
|
|
4542
|
+
(found) => `line ${found.line} ${found.name} as ${found.expected}`
|
|
4543
|
+
).join(", ") + ".",
|
|
4544
|
+
path
|
|
4545
|
+
)
|
|
4546
|
+
);
|
|
4547
|
+
}
|
|
4548
|
+
if (filtersTags(source).some((tag) => !/\slabel=/.test(tag))) {
|
|
4549
|
+
issues.push(
|
|
4550
|
+
issue(
|
|
4551
|
+
"FILTERS_LABEL_MISSING",
|
|
4552
|
+
'Filters from @flowdular/ui needs a translated label; without one it shows the English word "Filters" in every locale.',
|
|
4553
|
+
path
|
|
4554
|
+
)
|
|
4555
|
+
);
|
|
4556
|
+
}
|
|
4192
4557
|
}
|
|
4193
4558
|
return issues;
|
|
4194
4559
|
}
|
package/dist/index.js
CHANGED
|
@@ -2650,6 +2650,17 @@ var module_spec_schema_default = {
|
|
|
2650
2650
|
type: "array",
|
|
2651
2651
|
items: { $ref: "#/$defs/decision" },
|
|
2652
2652
|
uniqueItems: true
|
|
2653
|
+
},
|
|
2654
|
+
research: { $ref: "#/$defs/research" },
|
|
2655
|
+
adapters: {
|
|
2656
|
+
type: "array",
|
|
2657
|
+
items: { $ref: "#/$defs/adapter" },
|
|
2658
|
+
uniqueItems: true
|
|
2659
|
+
},
|
|
2660
|
+
templates: {
|
|
2661
|
+
type: "array",
|
|
2662
|
+
items: { $ref: "#/$defs/template" },
|
|
2663
|
+
uniqueItems: true
|
|
2653
2664
|
}
|
|
2654
2665
|
},
|
|
2655
2666
|
allOf: [
|
|
@@ -2667,7 +2678,10 @@ var module_spec_schema_default = {
|
|
|
2667
2678
|
settings: false,
|
|
2668
2679
|
agentTools: false,
|
|
2669
2680
|
outOfScope: false,
|
|
2670
|
-
decisions: false
|
|
2681
|
+
decisions: false,
|
|
2682
|
+
research: false,
|
|
2683
|
+
adapters: false,
|
|
2684
|
+
templates: false
|
|
2671
2685
|
}
|
|
2672
2686
|
}
|
|
2673
2687
|
}
|
|
@@ -2873,6 +2887,113 @@ var module_spec_schema_default = {
|
|
|
2873
2887
|
answer: { type: "string", minLength: 1 },
|
|
2874
2888
|
decidedBy: { enum: ["user", "default"] }
|
|
2875
2889
|
}
|
|
2890
|
+
},
|
|
2891
|
+
domain: {
|
|
2892
|
+
type: "string",
|
|
2893
|
+
maxLength: 253,
|
|
2894
|
+
pattern: "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$"
|
|
2895
|
+
},
|
|
2896
|
+
research: {
|
|
2897
|
+
type: "object",
|
|
2898
|
+
additionalProperties: false,
|
|
2899
|
+
required: ["adapter", "evidenceOwner"],
|
|
2900
|
+
properties: {
|
|
2901
|
+
adapter: {
|
|
2902
|
+
enum: [
|
|
2903
|
+
"model-native",
|
|
2904
|
+
"searxng",
|
|
2905
|
+
"firecrawl",
|
|
2906
|
+
"connector",
|
|
2907
|
+
"recorded"
|
|
2908
|
+
]
|
|
2909
|
+
},
|
|
2910
|
+
allowDomains: {
|
|
2911
|
+
type: "array",
|
|
2912
|
+
items: { $ref: "#/$defs/domain" },
|
|
2913
|
+
uniqueItems: true
|
|
2914
|
+
},
|
|
2915
|
+
denyDomains: {
|
|
2916
|
+
type: "array",
|
|
2917
|
+
items: { $ref: "#/$defs/domain" },
|
|
2918
|
+
uniqueItems: true
|
|
2919
|
+
},
|
|
2920
|
+
monthlyQueryBudget: { type: "integer", minimum: 1 },
|
|
2921
|
+
evidenceOwner: { $ref: "#/$defs/entityId" }
|
|
2922
|
+
}
|
|
2923
|
+
},
|
|
2924
|
+
adapter: {
|
|
2925
|
+
type: "object",
|
|
2926
|
+
additionalProperties: false,
|
|
2927
|
+
required: [
|
|
2928
|
+
"id",
|
|
2929
|
+
"direction",
|
|
2930
|
+
"connector",
|
|
2931
|
+
"operation",
|
|
2932
|
+
"port",
|
|
2933
|
+
"mapping"
|
|
2934
|
+
],
|
|
2935
|
+
properties: {
|
|
2936
|
+
id: {
|
|
2937
|
+
type: "string",
|
|
2938
|
+
pattern: "^[a-z][a-z0-9-]*(\\.[a-z][a-z0-9-]*)+$"
|
|
2939
|
+
},
|
|
2940
|
+
direction: { enum: ["source", "sink"] },
|
|
2941
|
+
connector: { type: "string", pattern: "^[a-z][a-z0-9-]{0,95}$" },
|
|
2942
|
+
operation: { type: "string", pattern: "^[a-z][a-z0-9-]{0,63}$" },
|
|
2943
|
+
port: {
|
|
2944
|
+
type: "string",
|
|
2945
|
+
maxLength: 96,
|
|
2946
|
+
pattern: "^[a-z][a-z0-9-]*(\\.[a-z][a-z0-9-]*)+$"
|
|
2947
|
+
},
|
|
2948
|
+
schedule: {
|
|
2949
|
+
anyOf: [
|
|
2950
|
+
{ type: "null" },
|
|
2951
|
+
{
|
|
2952
|
+
type: "string",
|
|
2953
|
+
maxLength: 100,
|
|
2954
|
+
pattern: "^[0-9a-z*,/-]+( [0-9a-z*,/-]+){4}$"
|
|
2955
|
+
}
|
|
2956
|
+
]
|
|
2957
|
+
},
|
|
2958
|
+
mapping: {
|
|
2959
|
+
type: "array",
|
|
2960
|
+
minItems: 1,
|
|
2961
|
+
items: { $ref: "#/$defs/adapterMapping" },
|
|
2962
|
+
uniqueItems: true
|
|
2963
|
+
},
|
|
2964
|
+
recorded: {
|
|
2965
|
+
type: "string",
|
|
2966
|
+
pattern: "^adapters/[a-z0-9][a-z0-9-]*\\.recorded\\.json$"
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
},
|
|
2970
|
+
adapterMapping: {
|
|
2971
|
+
type: "object",
|
|
2972
|
+
additionalProperties: false,
|
|
2973
|
+
required: ["to", "transform"],
|
|
2974
|
+
properties: {
|
|
2975
|
+
from: { type: "string", minLength: 1 },
|
|
2976
|
+
to: { type: "string", minLength: 1 },
|
|
2977
|
+
transform: { enum: ["rename", "constant", "format", "lookup"] },
|
|
2978
|
+
value: {
|
|
2979
|
+
anyOf: [{ type: "null" }, { type: "string", minLength: 1 }]
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
},
|
|
2983
|
+
template: {
|
|
2984
|
+
type: "object",
|
|
2985
|
+
additionalProperties: false,
|
|
2986
|
+
required: ["id", "title", "inputEntity", "format", "body"],
|
|
2987
|
+
properties: {
|
|
2988
|
+
id: { $ref: "#/$defs/entityId" },
|
|
2989
|
+
title: { type: "string", minLength: 1 },
|
|
2990
|
+
inputEntity: { $ref: "#/$defs/entityId" },
|
|
2991
|
+
format: { enum: ["pdf", "docx"] },
|
|
2992
|
+
body: {
|
|
2993
|
+
type: "string",
|
|
2994
|
+
pattern: "^templates/[a-z][a-z0-9-]*\\.md$"
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2876
2997
|
}
|
|
2877
2998
|
}
|
|
2878
2999
|
};
|
|
@@ -3039,6 +3160,15 @@ var project_schema_default = {
|
|
|
3039
3160
|
$ref: "#/$defs/githubAccount"
|
|
3040
3161
|
},
|
|
3041
3162
|
uniqueItems: true
|
|
3163
|
+
},
|
|
3164
|
+
labels: {
|
|
3165
|
+
type: "array",
|
|
3166
|
+
maxItems: 10,
|
|
3167
|
+
items: {
|
|
3168
|
+
type: "string",
|
|
3169
|
+
pattern: "^[A-Za-z0-9][A-Za-z0-9 ._:-]{0,49}$"
|
|
3170
|
+
},
|
|
3171
|
+
uniqueItems: true
|
|
3042
3172
|
}
|
|
3043
3173
|
}
|
|
3044
3174
|
},
|
|
@@ -3286,8 +3416,79 @@ var projectSchema = project_schema_default;
|
|
|
3286
3416
|
var moduleCatalogSchema = module_catalog_schema_default;
|
|
3287
3417
|
var moduleArtifactSchema = module_artifact_schema_default;
|
|
3288
3418
|
|
|
3419
|
+
// ../contracts/src/translations.ts
|
|
3420
|
+
var PLURAL_CATEGORIES = [
|
|
3421
|
+
"zero",
|
|
3422
|
+
"one",
|
|
3423
|
+
"two",
|
|
3424
|
+
"few",
|
|
3425
|
+
"many",
|
|
3426
|
+
"other"
|
|
3427
|
+
];
|
|
3428
|
+
var WHOLE_NUMBER_SAMPLES = [
|
|
3429
|
+
...Array.from({ length: 200 }, (_, index) => index),
|
|
3430
|
+
1e3,
|
|
3431
|
+
1e4,
|
|
3432
|
+
1e5,
|
|
3433
|
+
1e6,
|
|
3434
|
+
1e7,
|
|
3435
|
+
1e8,
|
|
3436
|
+
1e9
|
|
3437
|
+
];
|
|
3438
|
+
function requiredPluralCategories(locale) {
|
|
3439
|
+
const rules = new Intl.PluralRules(locale);
|
|
3440
|
+
const selected = /* @__PURE__ */ new Set(["other"]);
|
|
3441
|
+
for (const sample of WHOLE_NUMBER_SAMPLES) selected.add(rules.select(sample));
|
|
3442
|
+
return PLURAL_CATEGORIES.filter((category) => selected.has(category));
|
|
3443
|
+
}
|
|
3444
|
+
function pluralMember(bundle, key) {
|
|
3445
|
+
const dot = key.lastIndexOf(".");
|
|
3446
|
+
if (dot <= 0) return null;
|
|
3447
|
+
const category = key.slice(dot + 1);
|
|
3448
|
+
if (!PLURAL_CATEGORIES.includes(category)) return null;
|
|
3449
|
+
const base = key.slice(0, dot);
|
|
3450
|
+
return Object.hasOwn(bundle, base + ".other") ? { base, category } : null;
|
|
3451
|
+
}
|
|
3452
|
+
function translationKeys(bundle) {
|
|
3453
|
+
const keys = /* @__PURE__ */ new Set();
|
|
3454
|
+
for (const key of Object.keys(bundle)) {
|
|
3455
|
+
keys.add(pluralMember(bundle, key)?.base ?? key);
|
|
3456
|
+
}
|
|
3457
|
+
return [...keys].sort();
|
|
3458
|
+
}
|
|
3459
|
+
function pluralFamilyIssues(bundle, locale) {
|
|
3460
|
+
const families = /* @__PURE__ */ new Map();
|
|
3461
|
+
for (const key of Object.keys(bundle)) {
|
|
3462
|
+
const member = pluralMember(bundle, key);
|
|
3463
|
+
if (member === null) continue;
|
|
3464
|
+
const categories = families.get(member.base) ?? /* @__PURE__ */ new Set();
|
|
3465
|
+
categories.add(member.category);
|
|
3466
|
+
families.set(member.base, categories);
|
|
3467
|
+
}
|
|
3468
|
+
const required = requiredPluralCategories(locale);
|
|
3469
|
+
const known = new Intl.PluralRules(
|
|
3470
|
+
locale
|
|
3471
|
+
).resolvedOptions().pluralCategories;
|
|
3472
|
+
const issues = [];
|
|
3473
|
+
for (const base of [...families.keys()].sort()) {
|
|
3474
|
+
const categories = families.get(base);
|
|
3475
|
+
const missing = required.filter((category) => !categories.has(category));
|
|
3476
|
+
if (missing.length > 0) {
|
|
3477
|
+
issues.push(
|
|
3478
|
+
`${base} lacks ${missing.map((category) => base + "." + category).join(", ")} for ${locale}`
|
|
3479
|
+
);
|
|
3480
|
+
}
|
|
3481
|
+
for (const category of categories) {
|
|
3482
|
+
if (!known.includes(category)) {
|
|
3483
|
+
issues.push(`${base}.${category} is never selected for ${locale}`);
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
return issues;
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3289
3490
|
// ../contracts/src/index.ts
|
|
3290
|
-
var PLATFORM_API_VERSION = "0.1.
|
|
3491
|
+
var PLATFORM_API_VERSION = "0.1.21";
|
|
3291
3492
|
|
|
3292
3493
|
// src/module-templates.ts
|
|
3293
3494
|
function packageSuffix(id) {
|
|
@@ -3687,6 +3888,7 @@ function packageJson(model) {
|
|
|
3687
3888
|
"migrations",
|
|
3688
3889
|
"translations",
|
|
3689
3890
|
"spec",
|
|
3891
|
+
...spec.templates?.length ? ["templates"] : [],
|
|
3690
3892
|
"README.md"
|
|
3691
3893
|
],
|
|
3692
3894
|
scripts: {
|
|
@@ -4530,34 +4732,76 @@ export function create${names.pascal}ClientState() {
|
|
|
4530
4732
|
}
|
|
4531
4733
|
`;
|
|
4532
4734
|
}
|
|
4533
|
-
function
|
|
4534
|
-
if (count < 2) return "100%";
|
|
4535
|
-
const rest = Math.max(1, Math.floor(35 / (count - 1)));
|
|
4536
|
-
return index === 0 ? `${Math.max(1, 100 - rest * (count - 1))}%` : `${rest}%`;
|
|
4537
|
-
}
|
|
4538
|
-
function cellValue(field, namespace) {
|
|
4735
|
+
function scaffoldCell(field, namespace, index) {
|
|
4539
4736
|
const access7 = `record.${field.id}`;
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4737
|
+
const identity = index === 0;
|
|
4738
|
+
const priority = identity || field.state ? 1 : 2;
|
|
4739
|
+
const cell = (component, props, width, fieldPriority = priority, numeric = false) => ({
|
|
4740
|
+
component,
|
|
4741
|
+
markup: `<${component} ${props} />`,
|
|
4742
|
+
width: identity ? "auto" : width,
|
|
4743
|
+
priority: identity ? 1 : fieldPriority,
|
|
4744
|
+
numeric
|
|
4745
|
+
});
|
|
4746
|
+
switch (field.type) {
|
|
4747
|
+
case "enum":
|
|
4748
|
+
return cell(
|
|
4749
|
+
"CellTag",
|
|
4750
|
+
`label={t('${namespace}.${field.id}.' + ${access7})}` + (field.state ? " dot" : ""),
|
|
4751
|
+
"140px"
|
|
4752
|
+
);
|
|
4753
|
+
case "integer":
|
|
4754
|
+
case "decimal":
|
|
4755
|
+
return cell("CellNumber", `value={${access7}}`, "120px", priority, true);
|
|
4756
|
+
case "boolean":
|
|
4757
|
+
return cell("CellText", `value={String(${access7})}`, "100px");
|
|
4758
|
+
case "date":
|
|
4759
|
+
return cell("CellTime", `value={${access7}} kind="date"`, "140px");
|
|
4760
|
+
case "datetime":
|
|
4761
|
+
return cell("CellTime", `value={${access7}}`, "170px");
|
|
4762
|
+
case "reference":
|
|
4763
|
+
return cell("CellCode", `value={${access7}}`, "160px", 3);
|
|
4764
|
+
case "json":
|
|
4765
|
+
return cell(
|
|
4766
|
+
"CellText",
|
|
4767
|
+
`value={JSON.stringify(${access7})} mono`,
|
|
4768
|
+
"200px",
|
|
4769
|
+
3
|
|
4770
|
+
);
|
|
4771
|
+
case "text":
|
|
4772
|
+
return cell("CellText", `value={${access7}} wrap muted`, "240px", 3);
|
|
4773
|
+
default:
|
|
4774
|
+
return cell(
|
|
4775
|
+
"CellText",
|
|
4776
|
+
`value={${access7}}` + (identity ? " strong" : ""),
|
|
4777
|
+
"200px"
|
|
4778
|
+
);
|
|
4547
4779
|
}
|
|
4548
|
-
|
|
4780
|
+
}
|
|
4781
|
+
function scaffoldCells(model) {
|
|
4782
|
+
return model.columns.map(
|
|
4783
|
+
(field, index) => scaffoldCell(field, model.names.namespace, index)
|
|
4784
|
+
);
|
|
4785
|
+
}
|
|
4786
|
+
function cellImports(model) {
|
|
4787
|
+
const names = new Set(scaffoldCells(model).map((cell) => cell.component));
|
|
4788
|
+
if (model.columns.some((field) => !field.required)) names.add("CellMuted");
|
|
4789
|
+
return [...names].sort();
|
|
4549
4790
|
}
|
|
4550
4791
|
function tableColumns(model) {
|
|
4551
4792
|
const { columns, names } = model;
|
|
4793
|
+
const cells = scaffoldCells(model);
|
|
4552
4794
|
return columns.map((field, index) => {
|
|
4553
|
-
const
|
|
4554
|
-
const
|
|
4555
|
-
|
|
4795
|
+
const cell = cells[index];
|
|
4796
|
+
const markup = field.required ? cell.markup : `record.${field.id} === null
|
|
4797
|
+
? <CellMuted>{t('${names.namespace}.value.none')}</CellMuted>
|
|
4798
|
+
: ${cell.markup}`;
|
|
4556
4799
|
return ` {
|
|
4557
4800
|
key: '${field.id}',
|
|
4558
4801
|
header: t('${names.namespace}.table.column.${field.id}'),
|
|
4559
|
-
width: '${
|
|
4560
|
-
${
|
|
4802
|
+
width: '${cell.width}',
|
|
4803
|
+
${cell.priority > 1 ? ` priority: ${cell.priority},
|
|
4804
|
+
` : ""}${cell.numeric ? " numeric: true,\n" : ""} cell: (record) => ${markup},
|
|
4561
4805
|
},
|
|
4562
4806
|
`;
|
|
4563
4807
|
}).join("");
|
|
@@ -4592,7 +4836,8 @@ import { t } from '@flowdular/client';
|
|
|
4592
4836
|
import {
|
|
4593
4837
|
Alert,
|
|
4594
4838
|
Button,
|
|
4595
|
-
|
|
4839
|
+
${cellImports(model).map((name) => ` ${name},
|
|
4840
|
+
`).join("")} Icon,
|
|
4596
4841
|
PageHeader,
|
|
4597
4842
|
TableCard,
|
|
4598
4843
|
type TableColumn,
|
|
@@ -4880,6 +5125,74 @@ export default defineCliExtension({
|
|
|
4880
5125
|
});
|
|
4881
5126
|
`;
|
|
4882
5127
|
}
|
|
5128
|
+
function tsLiteral(value, depth) {
|
|
5129
|
+
if (typeof value === "string") return stringLiteral(value);
|
|
5130
|
+
if (value === null || typeof value !== "object") return String(value);
|
|
5131
|
+
const list = Array.isArray(value);
|
|
5132
|
+
const entries = list ? value.map((item) => tsLiteral(item, depth + 1)) : Object.entries(value).map(
|
|
5133
|
+
([key, item]) => `${key}: ${tsLiteral(item, depth + 1)}`
|
|
5134
|
+
);
|
|
5135
|
+
if (entries.length === 0) return list ? "[]" : "{}";
|
|
5136
|
+
const indent = " ".repeat(depth + 1);
|
|
5137
|
+
return `${list ? "[" : "{"}
|
|
5138
|
+
${entries.map((entry) => `${indent}${entry},
|
|
5139
|
+
`).join("")}${" ".repeat(depth)}${list ? "]" : "}"}`;
|
|
5140
|
+
}
|
|
5141
|
+
function researchFile(model, research) {
|
|
5142
|
+
return `import type { ModuleSpecResearch } from '@flowdular/contracts';
|
|
5143
|
+
|
|
5144
|
+
export const RESEARCH_CAPABILITIES = {
|
|
5145
|
+
search: 'research.search.v1',
|
|
5146
|
+
fetch: 'research.fetch.v1',
|
|
5147
|
+
evidence: 'research.evidence.v1',
|
|
5148
|
+
} as const;
|
|
5149
|
+
|
|
5150
|
+
export const ${model.names.constant}_RESEARCH = ${tsLiteral(research, 0)} as const satisfies ModuleSpecResearch;
|
|
5151
|
+
`;
|
|
5152
|
+
}
|
|
5153
|
+
function researchFixtures(research) {
|
|
5154
|
+
const host = research.allowDomains?.[0] ?? "example.com";
|
|
5155
|
+
const url = `https://${host}/example`;
|
|
5156
|
+
return json({
|
|
5157
|
+
queries: {
|
|
5158
|
+
example: [
|
|
5159
|
+
{
|
|
5160
|
+
url,
|
|
5161
|
+
title: "Example result",
|
|
5162
|
+
snippet: "Replace with a recorded search result.",
|
|
5163
|
+
source: host
|
|
5164
|
+
}
|
|
5165
|
+
]
|
|
5166
|
+
},
|
|
5167
|
+
pages: {
|
|
5168
|
+
[url]: {
|
|
5169
|
+
title: "Example result",
|
|
5170
|
+
text: "Replace with the text of the recorded page."
|
|
5171
|
+
}
|
|
5172
|
+
}
|
|
5173
|
+
});
|
|
5174
|
+
}
|
|
5175
|
+
function recordedFixture(adapter) {
|
|
5176
|
+
return json({
|
|
5177
|
+
adapter: adapter.id,
|
|
5178
|
+
operation: adapter.operation,
|
|
5179
|
+
calls: [{ input: {}, body: {} }]
|
|
5180
|
+
});
|
|
5181
|
+
}
|
|
5182
|
+
function adapterFile(name, adapter) {
|
|
5183
|
+
const constant = name.replace(/-/g, "_").toUpperCase();
|
|
5184
|
+
return `import type { ModuleSpecAdapter } from '@flowdular/contracts';
|
|
5185
|
+
|
|
5186
|
+
export const ${constant}_ADAPTER = ${tsLiteral(adapter, 0)} as const satisfies ModuleSpecAdapter;
|
|
5187
|
+
`;
|
|
5188
|
+
}
|
|
5189
|
+
function templateBody(spec, template) {
|
|
5190
|
+
const fields = (spec.entities ?? []).find((entity) => entity.id === template.inputEntity)?.fields.map((field) => field.id).join(", ");
|
|
5191
|
+
return `# ${template.title}
|
|
5192
|
+
|
|
5193
|
+
<!-- Rendered as ${template.format} from one ${template.inputEntity} record. Fields: ${fields}. -->
|
|
5194
|
+
`;
|
|
5195
|
+
}
|
|
4883
5196
|
var POLISH_LABELS = {
|
|
4884
5197
|
name: "Nazwa",
|
|
4885
5198
|
status: "Status",
|
|
@@ -4914,6 +5227,7 @@ function valueLabels(model, locale) {
|
|
|
4914
5227
|
function translation(locale, name, description, model) {
|
|
4915
5228
|
const columns = columnLabels(model, locale);
|
|
4916
5229
|
const values2 = valueLabels(model, locale);
|
|
5230
|
+
const optional = model.columns.some((field) => !field.required);
|
|
4917
5231
|
if (locale === "pl") {
|
|
4918
5232
|
return json({
|
|
4919
5233
|
"module.name": `Modu\u0142 ${name}`,
|
|
@@ -4925,12 +5239,16 @@ function translation(locale, name, description, model) {
|
|
|
4925
5239
|
"action.refresh": "Od\u015Bwie\u017C",
|
|
4926
5240
|
"table.title": "Rekordy",
|
|
4927
5241
|
"table.caption": `Rekordy modu\u0142u ${name}`,
|
|
4928
|
-
"table.count": "
|
|
5242
|
+
"table.count.one": "{count} rekord",
|
|
5243
|
+
"table.count.few": "{count} rekordy",
|
|
5244
|
+
"table.count.many": "{count} rekord\xF3w",
|
|
5245
|
+
"table.count.other": "{count} rekordu",
|
|
4929
5246
|
...columns,
|
|
4930
5247
|
"table.loading": "Wczytywanie rekord\xF3w\u2026",
|
|
4931
5248
|
"table.emptyTitle": "Brak rekord\xF3w",
|
|
4932
5249
|
"table.emptyHint": "Utworzone rekordy pojawi\u0105 si\u0119 w tym miejscu.",
|
|
4933
5250
|
...values2,
|
|
5251
|
+
...optional ? { "value.none": "Brak" } : {},
|
|
4934
5252
|
"error.load": "Nie uda\u0142o si\u0119 wczyta\u0107 rekord\xF3w.",
|
|
4935
5253
|
"error.request": "Operacja na rekordach nie powiod\u0142a si\u0119."
|
|
4936
5254
|
});
|
|
@@ -4945,12 +5263,18 @@ function translation(locale, name, description, model) {
|
|
|
4945
5263
|
"action.refresh": "Refresh",
|
|
4946
5264
|
"table.title": "Records",
|
|
4947
5265
|
"table.caption": `${name} records`,
|
|
4948
|
-
|
|
5266
|
+
...Object.fromEntries(
|
|
5267
|
+
requiredPluralCategories(locale).map((category) => [
|
|
5268
|
+
`table.count.${category}`,
|
|
5269
|
+
category === "one" ? "{count} record" : "{count} records"
|
|
5270
|
+
])
|
|
5271
|
+
),
|
|
4949
5272
|
...columns,
|
|
4950
5273
|
"table.loading": "Loading records\u2026",
|
|
4951
5274
|
"table.emptyTitle": "No records yet",
|
|
4952
5275
|
"table.emptyHint": "Records created in this workspace appear here.",
|
|
4953
5276
|
...values2,
|
|
5277
|
+
...optional ? { "value.none": "None" } : {},
|
|
4954
5278
|
"error.load": "Could not load records.",
|
|
4955
5279
|
"error.request": "The records operation failed."
|
|
4956
5280
|
});
|
|
@@ -5012,6 +5336,31 @@ function planScaffold(spec, specSource) {
|
|
|
5012
5336
|
files.set("src/cli/commands.json", cliCatalog(model));
|
|
5013
5337
|
files.set("src/cli/index.ts", cliEntry(model));
|
|
5014
5338
|
}
|
|
5339
|
+
if (spec.research) {
|
|
5340
|
+
files.set("src/research.ts", researchFile(model, spec.research));
|
|
5341
|
+
files.set("research-fixtures.json", researchFixtures(spec.research));
|
|
5342
|
+
}
|
|
5343
|
+
for (const adapter of spec.adapters ?? []) {
|
|
5344
|
+
const name = adapter.id.slice(spec.id.length + 1).replace(/\./g, "-");
|
|
5345
|
+
const paths = [
|
|
5346
|
+
`src/adapters/${name}.ts`,
|
|
5347
|
+
adapter.recorded ?? `adapters/${name}.recorded.json`
|
|
5348
|
+
];
|
|
5349
|
+
for (const path of paths) {
|
|
5350
|
+
if (files.has(path)) {
|
|
5351
|
+
throw new Error(
|
|
5352
|
+
`Adapter "${adapter.id}" and another adapter both map to ${path}.`
|
|
5353
|
+
);
|
|
5354
|
+
}
|
|
5355
|
+
}
|
|
5356
|
+
files.set(paths[0], adapterFile(name, adapter));
|
|
5357
|
+
files.set(paths[1], recordedFixture(adapter));
|
|
5358
|
+
}
|
|
5359
|
+
for (const template of spec.templates ?? []) {
|
|
5360
|
+
if (!files.has(template.body)) {
|
|
5361
|
+
files.set(template.body, templateBody(spec, template));
|
|
5362
|
+
}
|
|
5363
|
+
}
|
|
5015
5364
|
files.set("tests/module.test.ts", testFile(model));
|
|
5016
5365
|
for (const locale of /* @__PURE__ */ new Set(["en", ...spec.locales])) {
|
|
5017
5366
|
files.set(
|
|
@@ -5068,6 +5417,51 @@ function duplicateIssues(items, key, section) {
|
|
|
5068
5417
|
});
|
|
5069
5418
|
return issues;
|
|
5070
5419
|
}
|
|
5420
|
+
var MONTH_NAMES = "jan feb mar apr may jun jul aug sep oct nov dec".split(
|
|
5421
|
+
" "
|
|
5422
|
+
);
|
|
5423
|
+
var WEEKDAY_NAMES = "sun mon tue wed thu fri sat".split(" ");
|
|
5424
|
+
var CRON_FIELDS = [
|
|
5425
|
+
{ name: "minute", min: 0, max: 59 },
|
|
5426
|
+
{ name: "hour", min: 0, max: 23 },
|
|
5427
|
+
{ name: "day of month", min: 1, max: 31 },
|
|
5428
|
+
{ name: "month", min: 1, max: 12, names: MONTH_NAMES },
|
|
5429
|
+
{ name: "day of week", min: 0, max: 7, names: WEEKDAY_NAMES }
|
|
5430
|
+
];
|
|
5431
|
+
function cronIssue(expression) {
|
|
5432
|
+
const fields = expression.split(" ");
|
|
5433
|
+
if (fields.length !== 5) return "it needs five fields";
|
|
5434
|
+
for (const [index, field] of fields.entries()) {
|
|
5435
|
+
const spec = CRON_FIELDS[index];
|
|
5436
|
+
const names = "names" in spec ? spec.names : [];
|
|
5437
|
+
const value = (raw) => {
|
|
5438
|
+
const named = names.indexOf(raw);
|
|
5439
|
+
if (named >= 0) return named + spec.min;
|
|
5440
|
+
const number = /^\d{1,2}$/.test(raw) ? Number(raw) : Number.NaN;
|
|
5441
|
+
return number >= spec.min && number <= spec.max ? number : void 0;
|
|
5442
|
+
};
|
|
5443
|
+
const items = field.split(",");
|
|
5444
|
+
if (items.length > 32) return `${spec.name} lists too many values`;
|
|
5445
|
+
for (const item of items) {
|
|
5446
|
+
const [base = "", step, extra] = item.split("/");
|
|
5447
|
+
if (extra !== void 0 || base === "")
|
|
5448
|
+
return `${spec.name} has an unsupported value`;
|
|
5449
|
+
if (step !== void 0 && (!/^\d{1,2}$/.test(step) || Number(step) < 1 || Number(step) > spec.max - spec.min + 1))
|
|
5450
|
+
return `${spec.name} has an unsupported step`;
|
|
5451
|
+
if (base === "*") continue;
|
|
5452
|
+
const bounds = base.split("-");
|
|
5453
|
+
if (bounds.length > 2) return `${spec.name} has an unsupported range`;
|
|
5454
|
+
const from = value(bounds[0]);
|
|
5455
|
+
const to = bounds.length === 2 ? value(bounds[1]) : from;
|
|
5456
|
+
if (from === void 0 || to === void 0)
|
|
5457
|
+
return `${spec.name} must be between ${spec.min} and ${spec.max}`;
|
|
5458
|
+
if (bounds.length === 1 && step !== void 0)
|
|
5459
|
+
return `${spec.name} needs a range or * before a step`;
|
|
5460
|
+
if (to < from) return `${spec.name} range runs backwards`;
|
|
5461
|
+
}
|
|
5462
|
+
}
|
|
5463
|
+
return void 0;
|
|
5464
|
+
}
|
|
5071
5465
|
function moduleSpecIssues(value) {
|
|
5072
5466
|
const spec = value;
|
|
5073
5467
|
if (!spec || typeof spec !== "object" || spec.schemaVersion !== 2) return [];
|
|
@@ -5091,7 +5485,9 @@ function moduleSpecIssues(value) {
|
|
|
5091
5485
|
...duplicateIssues(spec.widgets, "id", "widgets"),
|
|
5092
5486
|
...duplicateIssues(spec.settings, "key", "settings"),
|
|
5093
5487
|
...duplicateIssues(spec.agentTools, "id", "agentTools"),
|
|
5094
|
-
...duplicateIssues(spec.decisions, "id", "decisions")
|
|
5488
|
+
...duplicateIssues(spec.decisions, "id", "decisions"),
|
|
5489
|
+
...duplicateIssues(spec.adapters, "id", "adapters"),
|
|
5490
|
+
...duplicateIssues(spec.templates, "id", "templates")
|
|
5095
5491
|
];
|
|
5096
5492
|
if (capabilities2.has("database") && entities.length === 0) {
|
|
5097
5493
|
issues.push(
|
|
@@ -5182,12 +5578,12 @@ function moduleSpecIssues(value) {
|
|
|
5182
5578
|
});
|
|
5183
5579
|
}
|
|
5184
5580
|
});
|
|
5185
|
-
const entityIssue = (entity, path) => {
|
|
5581
|
+
const entityIssue = (entity, path, key = "entity") => {
|
|
5186
5582
|
if (entity === void 0 || fieldsByEntity.has(entity)) return void 0;
|
|
5187
5583
|
return specIssue(
|
|
5188
5584
|
"SPEC_ENTITY_UNKNOWN",
|
|
5189
5585
|
`"${entity}" is not an entity of this specification.`,
|
|
5190
|
-
`${path}
|
|
5586
|
+
`${path}/${key}`
|
|
5191
5587
|
);
|
|
5192
5588
|
};
|
|
5193
5589
|
(spec.screens ?? []).forEach((screen, index) => {
|
|
@@ -5250,6 +5646,62 @@ function moduleSpecIssues(value) {
|
|
|
5250
5646
|
)
|
|
5251
5647
|
);
|
|
5252
5648
|
});
|
|
5649
|
+
const evidenceOwner = entityIssue(
|
|
5650
|
+
spec.research?.evidenceOwner,
|
|
5651
|
+
"/research",
|
|
5652
|
+
"evidenceOwner"
|
|
5653
|
+
);
|
|
5654
|
+
if (evidenceOwner) issues.push(evidenceOwner);
|
|
5655
|
+
(spec.templates ?? []).forEach((template, index) => {
|
|
5656
|
+
const unknownEntity = entityIssue(
|
|
5657
|
+
template.inputEntity,
|
|
5658
|
+
`/templates/${index}`,
|
|
5659
|
+
"inputEntity"
|
|
5660
|
+
);
|
|
5661
|
+
if (unknownEntity) issues.push(unknownEntity);
|
|
5662
|
+
});
|
|
5663
|
+
(spec.adapters ?? []).forEach((adapter, index) => {
|
|
5664
|
+
const path = `/adapters/${index}`;
|
|
5665
|
+
if (!adapter.id.startsWith(`${spec.id}.`)) {
|
|
5666
|
+
issues.push(
|
|
5667
|
+
specIssue(
|
|
5668
|
+
"SPEC_ADAPTER_ID_NAMESPACE",
|
|
5669
|
+
`Adapter "${adapter.id}" must start with the module id "${spec.id}.".`,
|
|
5670
|
+
`${path}/id`
|
|
5671
|
+
)
|
|
5672
|
+
);
|
|
5673
|
+
}
|
|
5674
|
+
if (adapter.direction === "source" && ![...modules].some((owner) => adapter.port.startsWith(`${owner}.`))) {
|
|
5675
|
+
issues.push(
|
|
5676
|
+
specIssue(
|
|
5677
|
+
"SPEC_ADAPTER_PORT_UNKNOWN",
|
|
5678
|
+
`Source adapter "${adapter.id}" writes through port "${adapter.port}", which belongs neither to this module nor to a declared dependency.`,
|
|
5679
|
+
`${path}/port`
|
|
5680
|
+
)
|
|
5681
|
+
);
|
|
5682
|
+
}
|
|
5683
|
+
const schedule = typeof adapter.schedule === "string" ? cronIssue(adapter.schedule) : void 0;
|
|
5684
|
+
if (schedule) {
|
|
5685
|
+
issues.push(
|
|
5686
|
+
specIssue(
|
|
5687
|
+
"SPEC_ADAPTER_SCHEDULE_INVALID",
|
|
5688
|
+
`Schedule of adapter "${adapter.id}" is not a five-field cron: ${schedule}.`,
|
|
5689
|
+
`${path}/schedule`
|
|
5690
|
+
)
|
|
5691
|
+
);
|
|
5692
|
+
}
|
|
5693
|
+
adapter.mapping.forEach((entry, entryIndex) => {
|
|
5694
|
+
const missing = entry.transform !== "constant" && entry.from === void 0 ? "from" : entry.transform !== "rename" && typeof entry.value !== "string" ? "value" : void 0;
|
|
5695
|
+
if (!missing) return;
|
|
5696
|
+
issues.push(
|
|
5697
|
+
specIssue(
|
|
5698
|
+
"SPEC_ADAPTER_MAPPING_INVALID",
|
|
5699
|
+
`A ${entry.transform} mapping of adapter "${adapter.id}" needs "${missing}".`,
|
|
5700
|
+
`${path}/mapping/${entryIndex}/${missing}`
|
|
5701
|
+
)
|
|
5702
|
+
);
|
|
5703
|
+
});
|
|
5704
|
+
});
|
|
5253
5705
|
if (capabilities2.has("client") && !(spec.screens ?? []).some(
|
|
5254
5706
|
(screen) => RENDERABLE_SCREEN_KINDS.has(screen.kind)
|
|
5255
5707
|
)) {
|
|
@@ -5391,19 +5843,14 @@ var ALLOWED = Object.freeze({ allowed: true });
|
|
|
5391
5843
|
var NO_POLICIES = Object.freeze([]);
|
|
5392
5844
|
|
|
5393
5845
|
// ../kernel/src/approval-grant.ts
|
|
5394
|
-
import
|
|
5846
|
+
import * as nodeCrypto2 from "node:crypto";
|
|
5395
5847
|
|
|
5396
5848
|
// ../kernel/src/keyring.ts
|
|
5397
|
-
import
|
|
5398
|
-
createCipheriv,
|
|
5399
|
-
createDecipheriv,
|
|
5400
|
-
createHash,
|
|
5401
|
-
randomBytes
|
|
5402
|
-
} from "node:crypto";
|
|
5849
|
+
import * as nodeCrypto from "node:crypto";
|
|
5403
5850
|
var KEYRING_KEY_BYTES = 32;
|
|
5404
5851
|
var KEYRING_MAX_PREVIOUS_KEYS = 8;
|
|
5405
5852
|
function keyFingerprint(key) {
|
|
5406
|
-
return createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
5853
|
+
return nodeCrypto.createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
5407
5854
|
}
|
|
5408
5855
|
function parsePreviousKeys(value, decode) {
|
|
5409
5856
|
if (!value) return [];
|
|
@@ -5475,7 +5922,7 @@ function canonical(value) {
|
|
|
5475
5922
|
return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${canonical(entry)}`).join(",")}}`;
|
|
5476
5923
|
}
|
|
5477
5924
|
function approvalInputDigest(input) {
|
|
5478
|
-
return
|
|
5925
|
+
return nodeCrypto2.createHash("sha256").update(canonical(input), "utf8").digest("hex");
|
|
5479
5926
|
}
|
|
5480
5927
|
function claimString(value, maximum = MAX_CLAIM_LENGTH) {
|
|
5481
5928
|
return typeof value === "string" && value.length >= 1 && value.length <= maximum && !/[\s\u0000]/.test(value) ? value : void 0;
|
|
@@ -5513,7 +5960,7 @@ function readClaims(value) {
|
|
|
5513
5960
|
};
|
|
5514
5961
|
}
|
|
5515
5962
|
function signature(key, signed) {
|
|
5516
|
-
return createHmac("sha256", key).update(signed, "utf8").digest();
|
|
5963
|
+
return nodeCrypto2.createHmac("sha256", key).update(signed, "utf8").digest();
|
|
5517
5964
|
}
|
|
5518
5965
|
function invalid(message) {
|
|
5519
5966
|
return { ok: false, reason: "APPROVAL_GRANT_INVALID", message };
|
|
@@ -5534,7 +5981,7 @@ function verifyApprovalGrant(keyring, token, expected, now = Date.now()) {
|
|
|
5534
5981
|
}
|
|
5535
5982
|
const expectedSignature = signature(key, `${prefix}.${keyId}.${payload}`);
|
|
5536
5983
|
const suppliedSignature = Buffer.from(supplied, "base64url");
|
|
5537
|
-
if (suppliedSignature.byteLength !== expectedSignature.byteLength || !timingSafeEqual(suppliedSignature, expectedSignature)) {
|
|
5984
|
+
if (suppliedSignature.byteLength !== expectedSignature.byteLength || !nodeCrypto2.timingSafeEqual(suppliedSignature, expectedSignature)) {
|
|
5538
5985
|
return invalid("The approval grant signature does not verify.");
|
|
5539
5986
|
}
|
|
5540
5987
|
let parsed;
|
|
@@ -6137,7 +6584,7 @@ import { dirname as dirname6, join as join5, relative as relative5 } from "node:
|
|
|
6137
6584
|
import { createRequire } from "node:module";
|
|
6138
6585
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
6139
6586
|
import { dirname as dirname4, join as join2 } from "node:path";
|
|
6140
|
-
var SDK_VERSION = "0.
|
|
6587
|
+
var SDK_VERSION = "0.4.0";
|
|
6141
6588
|
var LIBRARIES = /* @__PURE__ */ new Set([
|
|
6142
6589
|
"ai-provider",
|
|
6143
6590
|
"cli-protocol",
|
|
@@ -6317,6 +6764,113 @@ function failure(code, message, details) {
|
|
|
6317
6764
|
};
|
|
6318
6765
|
}
|
|
6319
6766
|
|
|
6767
|
+
// src/dom-properties.ts
|
|
6768
|
+
var DOM_PROPERTY_SPELLINGS = [
|
|
6769
|
+
"acceptCharset",
|
|
6770
|
+
"allowFullScreen",
|
|
6771
|
+
"autoCapitalize",
|
|
6772
|
+
"autoComplete",
|
|
6773
|
+
"autoCorrect",
|
|
6774
|
+
"autoFocus",
|
|
6775
|
+
"autoPlay",
|
|
6776
|
+
"charSet",
|
|
6777
|
+
"contentEditable",
|
|
6778
|
+
"crossOrigin",
|
|
6779
|
+
"defaultChecked",
|
|
6780
|
+
"defaultValue",
|
|
6781
|
+
"disablePictureInPicture",
|
|
6782
|
+
"disableRemotePlayback",
|
|
6783
|
+
"encType",
|
|
6784
|
+
"fetchPriority",
|
|
6785
|
+
"formAction",
|
|
6786
|
+
"formEncType",
|
|
6787
|
+
"formMethod",
|
|
6788
|
+
"formNoValidate",
|
|
6789
|
+
"formTarget",
|
|
6790
|
+
"httpEquiv",
|
|
6791
|
+
"imageSizes",
|
|
6792
|
+
"imageSrcSet",
|
|
6793
|
+
"inputMode",
|
|
6794
|
+
"itemID",
|
|
6795
|
+
"itemProp",
|
|
6796
|
+
"itemRef",
|
|
6797
|
+
"itemScope",
|
|
6798
|
+
"itemType",
|
|
6799
|
+
"maxLength",
|
|
6800
|
+
"noModule",
|
|
6801
|
+
"noValidate",
|
|
6802
|
+
"playsInline",
|
|
6803
|
+
"readOnly",
|
|
6804
|
+
"referrerPolicy",
|
|
6805
|
+
"spellCheck",
|
|
6806
|
+
"srcDoc",
|
|
6807
|
+
"srcLang",
|
|
6808
|
+
"srcSet",
|
|
6809
|
+
"tabIndex",
|
|
6810
|
+
"viewBox"
|
|
6811
|
+
];
|
|
6812
|
+
var SPELLINGS = new Map(
|
|
6813
|
+
DOM_PROPERTY_SPELLINGS.map((name) => [name.toLowerCase(), name])
|
|
6814
|
+
);
|
|
6815
|
+
function hostTagAttributes(source) {
|
|
6816
|
+
const tags = [];
|
|
6817
|
+
for (const match of source.matchAll(/<[a-z][a-z0-9-]*/g)) {
|
|
6818
|
+
const start = match.index + match[0].length;
|
|
6819
|
+
let depth = 0;
|
|
6820
|
+
let quote = "";
|
|
6821
|
+
let text = "";
|
|
6822
|
+
let end = start;
|
|
6823
|
+
for (; end < source.length; end += 1) {
|
|
6824
|
+
const character = source[end];
|
|
6825
|
+
if (quote !== "") {
|
|
6826
|
+
if (character === quote) quote = "";
|
|
6827
|
+
text += " ";
|
|
6828
|
+
continue;
|
|
6829
|
+
}
|
|
6830
|
+
if (depth > 0) {
|
|
6831
|
+
if (character === "{") depth += 1;
|
|
6832
|
+
else if (character === "}") depth -= 1;
|
|
6833
|
+
text += depth === 0 ? character : " ";
|
|
6834
|
+
continue;
|
|
6835
|
+
}
|
|
6836
|
+
if (character === "{") {
|
|
6837
|
+
depth = 1;
|
|
6838
|
+
text += character;
|
|
6839
|
+
continue;
|
|
6840
|
+
}
|
|
6841
|
+
if (character === '"' || character === "'") {
|
|
6842
|
+
quote = character;
|
|
6843
|
+
text += character;
|
|
6844
|
+
continue;
|
|
6845
|
+
}
|
|
6846
|
+
if (character === ">") break;
|
|
6847
|
+
text += character;
|
|
6848
|
+
}
|
|
6849
|
+
tags.push({ start, text });
|
|
6850
|
+
}
|
|
6851
|
+
return tags;
|
|
6852
|
+
}
|
|
6853
|
+
function domPropertyMisspellings(source) {
|
|
6854
|
+
const found = [];
|
|
6855
|
+
for (const tag of hostTagAttributes(source)) {
|
|
6856
|
+
for (const attribute of tag.text.matchAll(
|
|
6857
|
+
/(?<=\s)([A-Za-z][A-Za-z-]*)=/g
|
|
6858
|
+
)) {
|
|
6859
|
+
const name = attribute[1];
|
|
6860
|
+
const expected = SPELLINGS.get(name.toLowerCase());
|
|
6861
|
+
if (expected === void 0 || expected === name) continue;
|
|
6862
|
+
const index = tag.start + attribute.index;
|
|
6863
|
+
found.push({
|
|
6864
|
+
name,
|
|
6865
|
+
expected,
|
|
6866
|
+
index,
|
|
6867
|
+
line: source.slice(0, index).split("\n").length
|
|
6868
|
+
});
|
|
6869
|
+
}
|
|
6870
|
+
}
|
|
6871
|
+
return found.sort((left, right) => left.index - right.index);
|
|
6872
|
+
}
|
|
6873
|
+
|
|
6320
6874
|
// src/module-validate.ts
|
|
6321
6875
|
function issue(code, message, path, severity = "error") {
|
|
6322
6876
|
return { code, message, path, severity };
|
|
@@ -6506,6 +7060,7 @@ async function translationIssues(moduleRoot, manifest2, projectLocales) {
|
|
|
6506
7060
|
}
|
|
6507
7061
|
if (!manifest2.capabilities.includes("translations")) return issues;
|
|
6508
7062
|
const keySets = /* @__PURE__ */ new Map();
|
|
7063
|
+
const referenceBundleKeys = /* @__PURE__ */ new Set();
|
|
6509
7064
|
for (const locale of manifest2.locales) {
|
|
6510
7065
|
const path = `translations/${locale}.json`;
|
|
6511
7066
|
if (!await exists(join4(moduleRoot, path))) {
|
|
@@ -6523,7 +7078,21 @@ async function translationIssues(moduleRoot, manifest2, projectLocales) {
|
|
|
6523
7078
|
if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) {
|
|
6524
7079
|
throw new Error("Expected a JSON object.");
|
|
6525
7080
|
}
|
|
6526
|
-
|
|
7081
|
+
const strings = bundle;
|
|
7082
|
+
keySets.set(locale, translationKeys(strings));
|
|
7083
|
+
if (keySets.size === 1) {
|
|
7084
|
+
for (const key of Object.keys(strings)) referenceBundleKeys.add(key);
|
|
7085
|
+
}
|
|
7086
|
+
const plurals = pluralFamilyIssues(strings, locale);
|
|
7087
|
+
if (plurals.length > 0) {
|
|
7088
|
+
issues.push(
|
|
7089
|
+
issue(
|
|
7090
|
+
"TRANSLATION_PLURAL_INCOMPLETE",
|
|
7091
|
+
`${path} plural families do not match the ${locale} plural rules: ${plurals.join("; ")}.`,
|
|
7092
|
+
path
|
|
7093
|
+
)
|
|
7094
|
+
);
|
|
7095
|
+
}
|
|
6527
7096
|
} catch (error) {
|
|
6528
7097
|
issues.push(
|
|
6529
7098
|
issue(
|
|
@@ -6552,7 +7121,7 @@ async function translationIssues(moduleRoot, manifest2, projectLocales) {
|
|
|
6552
7121
|
)
|
|
6553
7122
|
);
|
|
6554
7123
|
}
|
|
6555
|
-
const referenceKeys = new Set(reference[1]);
|
|
7124
|
+
const referenceKeys = /* @__PURE__ */ new Set([...reference[1], ...referenceBundleKeys]);
|
|
6556
7125
|
const files = await clientSourceFiles(moduleRoot);
|
|
6557
7126
|
if (files.length > 0) {
|
|
6558
7127
|
const namespace = manifest2.id.split(".")[0] ?? manifest2.id;
|
|
@@ -6584,6 +7153,21 @@ async function translationIssues(moduleRoot, manifest2, projectLocales) {
|
|
|
6584
7153
|
}
|
|
6585
7154
|
return issues;
|
|
6586
7155
|
}
|
|
7156
|
+
function filtersTags(source) {
|
|
7157
|
+
const tags = [];
|
|
7158
|
+
for (const match of source.matchAll(/<Filters\b/g)) {
|
|
7159
|
+
let depth = 0;
|
|
7160
|
+
let end = match.index + match[0].length;
|
|
7161
|
+
for (; end < source.length; end += 1) {
|
|
7162
|
+
const character = source[end];
|
|
7163
|
+
if (character === "{") depth += 1;
|
|
7164
|
+
else if (character === "}") depth -= 1;
|
|
7165
|
+
else if (character === ">" && depth === 0) break;
|
|
7166
|
+
}
|
|
7167
|
+
tags.push(source.slice(match.index, end));
|
|
7168
|
+
}
|
|
7169
|
+
return tags;
|
|
7170
|
+
}
|
|
6587
7171
|
async function userInterfaceIssues(moduleRoot) {
|
|
6588
7172
|
const issues = [];
|
|
6589
7173
|
for (const file of await clientSourceFiles(moduleRoot)) {
|
|
@@ -6607,6 +7191,27 @@ async function userInterfaceIssues(moduleRoot) {
|
|
|
6607
7191
|
)
|
|
6608
7192
|
);
|
|
6609
7193
|
}
|
|
7194
|
+
const misspelled = domPropertyMisspellings(source);
|
|
7195
|
+
if (misspelled.length > 0) {
|
|
7196
|
+
issues.push(
|
|
7197
|
+
issue(
|
|
7198
|
+
"DOM_PROPERTY_CASING",
|
|
7199
|
+
"Host elements use Octane's DOM property spelling: " + misspelled.map(
|
|
7200
|
+
(found) => `line ${found.line} ${found.name} as ${found.expected}`
|
|
7201
|
+
).join(", ") + ".",
|
|
7202
|
+
path
|
|
7203
|
+
)
|
|
7204
|
+
);
|
|
7205
|
+
}
|
|
7206
|
+
if (filtersTags(source).some((tag) => !/\slabel=/.test(tag))) {
|
|
7207
|
+
issues.push(
|
|
7208
|
+
issue(
|
|
7209
|
+
"FILTERS_LABEL_MISSING",
|
|
7210
|
+
'Filters from @flowdular/ui needs a translated label; without one it shows the English word "Filters" in every locale.',
|
|
7211
|
+
path
|
|
7212
|
+
)
|
|
7213
|
+
);
|
|
7214
|
+
}
|
|
6610
7215
|
}
|
|
6611
7216
|
return issues;
|
|
6612
7217
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowdular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"flowdular": "./dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"ajv": "8.20.0",
|
|
17
17
|
"pg": "8.23.0",
|
|
18
18
|
"yaml": "2.9.0",
|
|
19
|
-
"@flowdular/sdk": "0.
|
|
19
|
+
"@flowdular/sdk": "0.4.0"
|
|
20
20
|
},
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"repository": {
|