@homepages/template-kit 0.2.0 → 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/CHANGELOG.md +222 -0
- package/README.md +96 -17
- package/dist/asset-modules.d.ts +81 -0
- package/dist/base.css +9 -0
- package/dist/cli/check/config.js +41 -0
- package/dist/cli/check/css.js +131 -0
- package/dist/cli/check/diagnostics.js +32 -0
- package/dist/cli/check/index.js +87 -0
- package/dist/cli/check/loader.js +146 -0
- package/dist/cli/check/paths.js +15 -0
- package/dist/cli/check/relativize.js +18 -0
- package/dist/cli/check/render-invariants.js +24 -0
- package/dist/cli/check/resolve-tool.js +38 -0
- package/dist/cli/check/section-assets.js +58 -0
- package/dist/cli/check/stages/deps.js +337 -0
- package/dist/cli/check/stages/lint.js +46 -0
- package/dist/cli/check/stages/render.js +101 -0
- package/dist/cli/check/stages/size.js +274 -0
- package/dist/cli/check/stages/tree.js +206 -0
- package/dist/cli/check/stages/typecheck.js +46 -0
- package/dist/cli/check/stages/validate/catalog-exhaustiveness.js +18 -0
- package/dist/cli/check/stages/validate/facts.js +18 -0
- package/dist/cli/check/stages/validate/formatter-contract.js +14 -0
- package/dist/cli/check/stages/validate/group-contract.js +21 -0
- package/dist/cli/check/stages/validate/index.js +66 -0
- package/dist/cli/check/stages/validate/list-scalar-contract.js +22 -0
- package/dist/cli/check/stages/validate/nav-contract.js +93 -0
- package/dist/cli/check/stages/validate/nested-slot-contract.js +12 -0
- package/dist/cli/check/stages/validate/object-list-contract.js +31 -0
- package/dist/cli/check/stages/validate/orchestrator.js +241 -0
- package/dist/cli/check/stages/validate/produced-by-contract.js +18 -0
- package/dist/cli/check/stages/validate/row-contract.js +31 -0
- package/dist/cli/check/stages/validate/select-contract.js +13 -0
- package/dist/cli/check/stages/validate/source-contract.js +21 -0
- package/dist/cli/check/stages/validate/variant-contract.js +15 -0
- package/dist/cli/check/workspace.js +86 -0
- package/dist/cli/dev/build-css.js +91 -0
- package/dist/cli/dev/catalog.js +35 -0
- package/dist/cli/dev/compose-template.js +38 -0
- package/dist/cli/dev/content-override.js +58 -0
- package/dist/cli/dev/discover.js +35 -0
- package/dist/cli/dev/fill-state.js +75 -0
- package/dist/cli/dev/index.js +32 -0
- package/dist/cli/dev/inspect.js +38 -0
- package/dist/cli/dev/island-bootstrap.js +38 -0
- package/dist/cli/dev/island-map.js +35 -0
- package/dist/cli/dev/island-transform.js +31 -0
- package/dist/cli/dev/manifest-instances.js +31 -0
- package/dist/cli/dev/render-section.js +24 -0
- package/dist/cli/dev/screenshot-target.js +24 -0
- package/dist/cli/dev/section-page.js +54 -0
- package/dist/cli/dev/server.js +480 -0
- package/dist/cli/dev/slot-schema.js +12 -0
- package/dist/cli/dev/structure-summary.js +118 -0
- package/dist/cli/dev/tailwind.js +32 -0
- package/dist/cli/dev/vite-server.js +33 -0
- package/dist/cli/dev/workspace.js +63 -0
- package/dist/cli/link/index.js +74 -0
- package/dist/cli/link/overlay.js +59 -0
- package/dist/cli/link/watch.js +25 -0
- package/dist/cli/new/emit.js +48 -0
- package/dist/cli/new/index.js +69 -0
- package/dist/cli/new/scaffold/section/_Renderer.tsx +20 -0
- package/dist/cli/new/scaffold/section/_fill-spec.ts +18 -0
- package/dist/cli/new/scaffold/section/_fixtures.ts +13 -0
- package/dist/cli/new/scaffold/section/_schema.ts +24 -0
- package/dist/cli/new/scaffold/template/_manifest.json +9 -0
- package/dist/cli/new/scaffold/template/sections/hero/ExpandableText.tsx +45 -0
- package/dist/cli/new/scaffold/template/sections/hero/Renderer.tsx +40 -0
- package/dist/cli/new/scaffold/template/sections/hero/components/Feature.tsx +14 -0
- package/dist/cli/new/scaffold/template/sections/hero/fill-spec.ts +29 -0
- package/dist/cli/new/scaffold/template/sections/hero/fixtures.ts +41 -0
- package/dist/cli/new/scaffold/template/sections/hero/schema.ts +60 -0
- package/dist/cli/new/scaffold/template/theme.css +24 -0
- package/dist/cli/new/scaffold/template/theme.ts +27 -0
- package/dist/cli/new/scaffold-assets.js +20 -0
- package/dist/cli/pack/collect.js +44 -0
- package/dist/cli/pack/guards.js +57 -0
- package/dist/cli/pack/index.js +66 -0
- package/dist/cli/pack/manifest.js +15 -0
- package/dist/cli/pack/zip.js +86 -0
- package/dist/cli/theme/generate.js +43 -0
- package/dist/cli/theme/index.js +33 -0
- package/dist/cli/theme/load-theme.js +69 -0
- package/dist/cli.js +100 -16
- package/dist/contracts/fill-treatments.js +47 -0
- package/dist/design-system/theme.d.ts +30 -300
- package/dist/design-system/theme.js +112 -90
- package/dist/dev-client/assets/index-DfEfrp6P.css +1 -0
- package/dist/dev-client/assets/index-bpMP0b0W.js +50 -0
- package/dist/dev-client/index.html +13 -0
- package/dist/eslint/is-client-file.d.ts +4 -0
- package/dist/eslint/rules/no-hex.js +78 -6
- package/dist/eslint.js +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -2
- package/dist/islands/detect.d.ts +16 -0
- package/dist/islands/detect.js +22 -0
- package/dist/islands/discover.d.ts +5 -0
- package/dist/islands/discover.js +19 -0
- package/dist/islands/esbuild-plugin.d.ts +13 -0
- package/dist/islands/esbuild-plugin.js +39 -0
- package/dist/islands/wrap.d.ts +11 -0
- package/dist/islands/wrap.js +48 -0
- package/dist/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +77 -0
- package/dist/node_modules/magic-string/dist/magic-string.es.js +939 -0
- package/dist/package.js +1 -1
- package/dist/primitives/Image.js +1 -1
- package/dist/schema/fill-spec.d.ts +80 -590
- package/dist/schema/fixture-schema.d.ts +5 -81
- package/dist/schema/manifest.d.ts +39 -475
- package/dist/schema/resolve-section-ref.js +10 -0
- package/dist/schema/rows.js +10 -0
- package/dist/schema/section-nav.js +9 -0
- package/dist/schema/section-schema.d.ts +51 -437
- package/dist/schema/slot-types.d.ts +12 -16
- package/dist/ssr.d.ts +31 -0
- package/dist/ssr.js +46 -0
- package/dist/styles.css +31 -88
- package/docs/INDEX.md +12 -3
- package/docs/assets.md +128 -0
- package/docs/check.md +124 -0
- package/docs/dev.md +187 -0
- package/docs/eslint.md +18 -8
- package/docs/islands.md +5 -2
- package/docs/llms.txt +59 -9
- package/docs/new.md +27 -0
- package/docs/overview.md +57 -0
- package/docs/pack.md +46 -0
- package/docs/primitives.md +10 -6
- package/docs/quickstart.md +102 -0
- package/docs/recipes/INDEX.md +27 -0
- package/docs/recipes/bind-property-fact.md +58 -0
- package/docs/recipes/collection-slot.md +100 -0
- package/docs/recipes/fill-spec-decision.md +66 -0
- package/docs/recipes/fixture-states.md +68 -0
- package/docs/recipes/image-slot-crop.md +98 -0
- package/docs/recipes/interactive-island.md +100 -0
- package/docs/recipes/organize-section-folder.md +72 -0
- package/docs/recipes/prepare-submission.md +55 -0
- package/docs/recipes/second-template.md +49 -0
- package/docs/recipes/select-slot.md +59 -0
- package/docs/recipes/static-asset.md +103 -0
- package/docs/recipes/third-party-package.md +90 -0
- package/docs/rules/INDEX.md +14 -5
- package/docs/rules/bundle-binary-asset.md +83 -0
- package/docs/rules/bundle-incomplete.md +2 -2
- package/docs/rules/css-reason.md +3 -3
- package/docs/rules/fixtures-invalid.md +96 -0
- package/docs/rules/license-denied.md +11 -3
- package/docs/rules/manifest-invalid.md +99 -0
- package/docs/rules/no-bare-css-import.md +8 -8
- package/docs/rules/no-css-import-from-render-path.md +7 -8
- package/docs/rules/no-hex.md +76 -10
- package/docs/rules/no-templates.md +87 -0
- package/docs/rules/parse-error.md +76 -0
- package/docs/rules/schema-invalid.md +96 -0
- package/docs/rules/size-assets.md +88 -0
- package/docs/rules/size-island-bundle.md +123 -0
- package/docs/rules/size-section-css.md +19 -14
- package/docs/schema-system.md +28 -28
- package/docs/theme-and-css.md +157 -92
- package/docs/vocabulary.md +98 -0
- package/package.json +14 -11
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>template-kit dev</title>
|
|
7
|
+
<script type="module" crossorigin src="/dev-client/assets/index-bpMP0b0W.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/dev-client/assets/index-DfEfrp6P.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -1,8 +1,77 @@
|
|
|
1
1
|
import { docsPathForRule } from "../../rules/registry.js";
|
|
2
2
|
|
|
3
3
|
//#region src/eslint/rules/no-hex.ts
|
|
4
|
-
const COLOR_FN = /(?:oklch|oklab|rgba?|hsla?|color-mix)\s*\([^)]*\)/;
|
|
5
4
|
const HEX = /#(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{4}|[0-9a-fA-F]{3})\b/g;
|
|
5
|
+
const SEPARATOR = /[\s_]/;
|
|
6
|
+
const TRIM_SEPARATORS = /^[\s_]+|[\s_]+$/g;
|
|
7
|
+
const PERCENTAGE = /^[+-]?(?:\d+\.?\d*|\.\d+)%$/;
|
|
8
|
+
const VAR_REF = /^var\((.*)\)$/s;
|
|
9
|
+
const NESTED_COLOR_MIX = /^color-mix[\s_]*\((.*)\)$/s;
|
|
10
|
+
const CUSTOM_PROPERTY_NAME = /^--[A-Za-z0-9_-]+$/;
|
|
11
|
+
const PALETTE_FREE_KEYWORDS = /* @__PURE__ */ new Set(["transparent", "currentcolor"]);
|
|
12
|
+
function splitTopLevel(text, isSeparator) {
|
|
13
|
+
const parts = [];
|
|
14
|
+
let depth = 0;
|
|
15
|
+
let current = "";
|
|
16
|
+
for (const char of text) {
|
|
17
|
+
if (char === "(") depth += 1;
|
|
18
|
+
else if (char === ")") depth -= 1;
|
|
19
|
+
if (depth === 0 && isSeparator(char)) {
|
|
20
|
+
if (current !== "") parts.push(current);
|
|
21
|
+
current = "";
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
current += char;
|
|
25
|
+
}
|
|
26
|
+
if (current !== "") parts.push(current);
|
|
27
|
+
return parts;
|
|
28
|
+
}
|
|
29
|
+
function findColorFunctionCalls(text) {
|
|
30
|
+
const head = /(?:oklch|oklab|rgba?|hsla?|color-mix)[\s_]*\(/g;
|
|
31
|
+
const calls = [];
|
|
32
|
+
let match;
|
|
33
|
+
while (match = head.exec(text)) {
|
|
34
|
+
const open = match.index + match[0].length - 1;
|
|
35
|
+
let depth = 0;
|
|
36
|
+
let close = -1;
|
|
37
|
+
for (let i = open; i < text.length; i += 1) if (text[i] === "(") depth += 1;
|
|
38
|
+
else if (text[i] === ")") {
|
|
39
|
+
depth -= 1;
|
|
40
|
+
if (depth === 0) {
|
|
41
|
+
close = i;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (close === -1) continue;
|
|
46
|
+
calls.push({
|
|
47
|
+
raw: text.slice(match.index, close + 1),
|
|
48
|
+
name: match[0].replace(/[\s_]*\($/, "").toLowerCase(),
|
|
49
|
+
args: text.slice(open + 1, close)
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return calls;
|
|
53
|
+
}
|
|
54
|
+
function isThemeDerivedColor(token) {
|
|
55
|
+
const value = token.replace(TRIM_SEPARATORS, "");
|
|
56
|
+
if (PALETTE_FREE_KEYWORDS.has(value.toLowerCase())) return true;
|
|
57
|
+
const varRef = VAR_REF.exec(value);
|
|
58
|
+
if (varRef) {
|
|
59
|
+
const [name, ...fallback] = splitTopLevel(varRef[1] ?? "", (char) => char === ",");
|
|
60
|
+
if (name === void 0 || !CUSTOM_PROPERTY_NAME.test(name.replace(TRIM_SEPARATORS, ""))) return false;
|
|
61
|
+
return fallback.length === 0 || isThemeDerivedColor(fallback.join(","));
|
|
62
|
+
}
|
|
63
|
+
const nested = NESTED_COLOR_MIX.exec(value);
|
|
64
|
+
return nested !== null && isThemeDerivedColorMix(nested[1] ?? "");
|
|
65
|
+
}
|
|
66
|
+
function isThemeDerivedColorMix(args) {
|
|
67
|
+
const [interpolation, ...colors] = splitTopLevel(args, (char) => char === ",");
|
|
68
|
+
if (interpolation === void 0 || !/^in[\s_]/.test(interpolation.replace(TRIM_SEPARATORS, ""))) return false;
|
|
69
|
+
if (colors.length === 0) return false;
|
|
70
|
+
return colors.every((color) => {
|
|
71
|
+
const [colorToken, ...rest] = splitTopLevel(color, (char) => SEPARATOR.test(char)).filter((token) => !PERCENTAGE.test(token));
|
|
72
|
+
return colorToken !== void 0 && rest.length === 0 && isThemeDerivedColor(colorToken);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
6
75
|
const COLOR_UTILITY_PREFIXES = [
|
|
7
76
|
"bg",
|
|
8
77
|
"text",
|
|
@@ -74,16 +143,19 @@ const noHex = {
|
|
|
74
143
|
url: docsPathForRule("no-hex")
|
|
75
144
|
},
|
|
76
145
|
schema: [],
|
|
77
|
-
messages: {
|
|
146
|
+
messages: {
|
|
147
|
+
hardCodedColor: "`{{value}}` is a hard-coded colour — a section carries no palette of its own, or it breaks the first time another template reuses it. Fix: use one of your theme's colour utilities; if the value is genuinely brand decoration with no token yet, add it to `colors` in the template's `theme.ts` and use the `bg-<name>` / `text-<name>` utility it compiles to.",
|
|
148
|
+
hardCodedColorFunction: "`{{value}}` bakes a colour into a section — a section carries no palette of its own, or it breaks the first time another template reuses it. Fix: derive the colour from the theme instead. A `color-mix()` over theme vars is allowed (e.g. `color-mix(in srgb, var(--tr-color-primary) 80%, var(--tr-color-surface))`, or mix toward `transparent` for a translucent tint) — only a hard-coded argument makes it a violation."
|
|
149
|
+
}
|
|
78
150
|
},
|
|
79
151
|
create(context) {
|
|
80
152
|
function check(node, text) {
|
|
81
|
-
const
|
|
82
|
-
|
|
153
|
+
for (const call of findColorFunctionCalls(text)) {
|
|
154
|
+
if (call.name === "color-mix" && isThemeDerivedColorMix(call.args)) continue;
|
|
83
155
|
context.report({
|
|
84
156
|
node,
|
|
85
|
-
messageId: "
|
|
86
|
-
data: { value:
|
|
157
|
+
messageId: "hardCodedColorFunction",
|
|
158
|
+
data: { value: call.raw }
|
|
87
159
|
});
|
|
88
160
|
return;
|
|
89
161
|
}
|
package/dist/eslint.js
CHANGED
|
@@ -55,7 +55,7 @@ const templateKitConfig = [
|
|
|
55
55
|
"template-kit/no-raw-element": "error",
|
|
56
56
|
"template-kit/image-bare-needs-reason": "error",
|
|
57
57
|
"template-kit/slot-marker-literal": "error",
|
|
58
|
-
"template-kit/no-hex": "
|
|
58
|
+
"template-kit/no-hex": "warn",
|
|
59
59
|
"template-kit/no-css-import-from-render-path": "error"
|
|
60
60
|
}
|
|
61
61
|
},
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ResponsiveImage, ResponsiveSource } from "./contracts/image-descriptor.js";
|
|
2
2
|
import { Coordinates, FloorplanAssignment, PropertyFacts, UnitRow } from "./schema/property-facts.js";
|
|
3
|
+
import "./asset-modules.js";
|
|
3
4
|
import { COLLECTIONS, CONTENT_SLOT_TYPES, CollectionField, CollectionIdKey, CollectionOwnership, ContentSlotType, DECISION_TYPES, DERIVED_INPUT_FIELDS, DecisionType, DerivedInputName, FORMATTER_NAMES, FormatterName, REFERRAL_FIELDS, REFERRAL_IMAGE_FIELDS, REF_SLOT_TYPES, RefSlotType, ReferralField, ReferralImageField, SLOT_TYPES, SOURCE_FIELDS, SlotType, SourceFieldContainer, SourceFieldDescriptor, SourceFieldName, SourceFieldValueType, WritebackTarget, collectionForSlot } from "./contracts/slot-catalog.js";
|
|
4
5
|
import { AddressParts, TRANSFORMS, TRANSFORM_NAMES, TransformDescriptor, TransformFn, TransformInput, TransformName, TransformUnit } from "./contracts/transforms.js";
|
|
5
6
|
import { VariantSelectorFn, VariantsMeta, makeResolveVariants } from "./schema/resolve-variants.js";
|
|
@@ -24,7 +25,7 @@ import { SlotGroup } from "./primitives/SlotGroup.js";
|
|
|
24
25
|
import { SlotItem } from "./primitives/SlotItem.js";
|
|
25
26
|
import "./primitives/index.js";
|
|
26
27
|
import { ATTR_SECTION_INSTANCE_ID, ATTR_SLOT_GROUP, ATTR_SLOT_ID, ATTR_SLOT_ITEM, ATTR_SLOT_TEXT_LEAF, ATTR_TR_ENHANCE } from "./contracts/markers.js";
|
|
27
|
-
import {
|
|
28
|
+
import { TokenNameSchema, TokenTheme, TokenThemeSchema, compileThemeToCss } from "./design-system/theme.js";
|
|
28
29
|
//#region src/index.d.ts
|
|
29
30
|
/**
|
|
30
31
|
* The published version of this kit.
|
|
@@ -37,4 +38,4 @@ import { COLOR_ROLE_VARS, ColorRole, FONT_ROLE_VARS, LAYOUT_VARS, RADIUS_VARS, S
|
|
|
37
38
|
*/
|
|
38
39
|
declare const KIT_VERSION: string;
|
|
39
40
|
//#endregion
|
|
40
|
-
export { ATTR_ISLAND_ID, ATTR_ISLAND_KEY, ATTR_ISLAND_PROPS, ATTR_SECTION_INSTANCE_ID, ATTR_SLOT_GROUP, ATTR_SLOT_ID, ATTR_SLOT_ITEM, ATTR_SLOT_TEXT_LEAF, ATTR_TR_ENHANCE, type AddressParts, COLLECTIONS,
|
|
41
|
+
export { ATTR_ISLAND_ID, ATTR_ISLAND_KEY, ATTR_ISLAND_PROPS, ATTR_SECTION_INSTANCE_ID, ATTR_SLOT_GROUP, ATTR_SLOT_ID, ATTR_SLOT_ITEM, ATTR_SLOT_TEXT_LEAF, ATTR_TR_ENHANCE, type AddressParts, COLLECTIONS, CONTENT_SLOT_TYPES, type CollectionField, type CollectionIdKey, type CollectionOwnership, ContentSlot, type ContentSlotType, type Coordinates, DECISION_TYPES, DERIVED_INPUT_FIELDS, Decision, type DecisionType, type DerivedInputName, FORMATTER_NAMES, FillSpec, type FillSpecShape, type FixtureModule, FixtureModuleShape, type FixtureOverride, type FloorplanAssignment, type FormatterName, type FrameConfig, ISLAND_ELEMENT, Image, type ImageCollectionValue, type ImageValue, IslandComponent, IslandEditorOptions, IslandMarker, type IslandMarkerProps, IslandModule, IslandProps, IslandPropsError, KIT_VERSION, OptionDef, type OptionValue, type PicturePlan, type PictureSourceSpec, type PoiRow, type PropertyFacts, REFERRAL_FIELDS, REFERRAL_IMAGE_FIELDS, REF_SLOT_TYPES, type RefSlotType, type ReferralField, type ReferralImageField, type ResolvedFixture, type ResponsiveImage, type ResponsiveSource, SLOT_TYPES, SLOT_TYPE_DESCRIPTORS, SOURCE_FIELDS, Section, SectionMeta, type SectionMetaShape, type SectionNav, type SectionProps, SectionSchema, type SectionSchemaResolved, type SectionSchemaShape, ShieldMode, Slot, SlotDef, type Slot$1 as SlotDefinition, SlotGroup, SlotGroupDef, type SlotGroupDefShape, SlotItem, type SlotType, type SlotValue, type SourceFieldContainer, type SourceFieldDescriptor, type SourceFieldName, type SourceFieldValueType, TRANSFORMS, TRANSFORM_NAMES, TemplateManifest, type TemplateManifestShape, TokenNameSchema, type TokenTheme, TokenThemeSchema, type TransformDescriptor, type TransformFn, type TransformInput, type TransformName, type TransformUnit, type UnitRow, VERIFICATION_WIDTHS, type VariantSelectorFn, type VariantsMeta, type VerificationWidth, type WritebackTarget, buildFixtureSet, buildInvariantFixtures, collectionForSlot, compileThemeToCss, defaultForSlotType, derived, deserializeIslandProps, direct, islandId, makeResolveVariants, serializeIslandProps, slotDefTypes };
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import { Section } from "./primitives/Section.js";
|
|
|
17
17
|
import { Slot } from "./primitives/Slot.js";
|
|
18
18
|
import { SlotGroup } from "./primitives/SlotGroup.js";
|
|
19
19
|
import { SlotItem } from "./primitives/SlotItem.js";
|
|
20
|
-
import {
|
|
20
|
+
import { TokenNameSchema, TokenThemeSchema, compileThemeToCss } from "./design-system/theme.js";
|
|
21
21
|
|
|
22
22
|
//#region src/index.ts
|
|
23
23
|
/**
|
|
@@ -32,4 +32,4 @@ import { COLOR_ROLE_VARS, FONT_ROLE_VARS, LAYOUT_VARS, RADIUS_VARS, SHADOW_VARS,
|
|
|
32
32
|
const KIT_VERSION = version;
|
|
33
33
|
|
|
34
34
|
//#endregion
|
|
35
|
-
export { ATTR_ISLAND_ID, ATTR_ISLAND_KEY, ATTR_ISLAND_PROPS, ATTR_SECTION_INSTANCE_ID, ATTR_SLOT_GROUP, ATTR_SLOT_ID, ATTR_SLOT_ITEM, ATTR_SLOT_TEXT_LEAF, ATTR_TR_ENHANCE, COLLECTIONS,
|
|
35
|
+
export { ATTR_ISLAND_ID, ATTR_ISLAND_KEY, ATTR_ISLAND_PROPS, ATTR_SECTION_INSTANCE_ID, ATTR_SLOT_GROUP, ATTR_SLOT_ID, ATTR_SLOT_ITEM, ATTR_SLOT_TEXT_LEAF, ATTR_TR_ENHANCE, COLLECTIONS, CONTENT_SLOT_TYPES, ContentSlot, DECISION_TYPES, DERIVED_INPUT_FIELDS, Decision, FORMATTER_NAMES, FillSpec, FixtureModuleShape, ISLAND_ELEMENT, Image, IslandMarker, IslandPropsError, KIT_VERSION, OptionDef, REFERRAL_FIELDS, REFERRAL_IMAGE_FIELDS, REF_SLOT_TYPES, SLOT_TYPES, SLOT_TYPE_DESCRIPTORS, SOURCE_FIELDS, Section, SectionMeta, SectionSchema, Slot, SlotDef, SlotGroup, SlotGroupDef, SlotItem, TRANSFORMS, TRANSFORM_NAMES, TemplateManifest, TokenNameSchema, TokenThemeSchema, VERIFICATION_WIDTHS, buildFixtureSet, buildInvariantFixtures, collectionForSlot, compileThemeToCss, defaultForSlotType, derived, deserializeIslandProps, direct, islandId, makeResolveVariants, serializeIslandProps, slotDefTypes };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { hasClientDirective } from "../eslint/is-client-file.js";
|
|
2
|
+
//#region src/islands/detect.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* True iff `file` is a client component — an on-disk source file whose directive
|
|
5
|
+
* prologue is `"use client"`. Returns false for an unreadable or absent path.
|
|
6
|
+
*/
|
|
7
|
+
declare function isClientComponentFile(file: string): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Compose an island key: `<sectionKey>:<componentName>` (e.g.
|
|
10
|
+
* `spw-essential/floorplan:UnitFilter`). The key is what a marker in the DOM
|
|
11
|
+
* carries and what the browser loader resolves the client module by, so the
|
|
12
|
+
* emitter and the loader must derive it identically.
|
|
13
|
+
*/
|
|
14
|
+
declare function islandKey(sectionKey: string, componentName: string): string;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { hasClientDirective, isClientComponentFile, islandKey };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { hasClientDirective, isClientFile } from "../eslint/is-client-file.js";
|
|
2
|
+
|
|
3
|
+
//#region src/islands/detect.ts
|
|
4
|
+
/**
|
|
5
|
+
* True iff `file` is a client component — an on-disk source file whose directive
|
|
6
|
+
* prologue is `"use client"`. Returns false for an unreadable or absent path.
|
|
7
|
+
*/
|
|
8
|
+
function isClientComponentFile(file) {
|
|
9
|
+
return isClientFile(file);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Compose an island key: `<sectionKey>:<componentName>` (e.g.
|
|
13
|
+
* `spw-essential/floorplan:UnitFilter`). The key is what a marker in the DOM
|
|
14
|
+
* carries and what the browser loader resolves the client module by, so the
|
|
15
|
+
* emitter and the loader must derive it identically.
|
|
16
|
+
*/
|
|
17
|
+
function islandKey(sectionKey, componentName) {
|
|
18
|
+
return `${sectionKey}:${componentName}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { hasClientDirective, isClientComponentFile, islandKey };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isClientComponentFile } from "./detect.js";
|
|
2
|
+
import { extname, join } from "node:path";
|
|
3
|
+
import { readdir } from "node:fs/promises";
|
|
4
|
+
|
|
5
|
+
//#region src/islands/discover.ts
|
|
6
|
+
const COMPONENT_EXTS = /* @__PURE__ */ new Set([".tsx", ".jsx"]);
|
|
7
|
+
/** Every `"use client"` component file anywhere under a section directory (recursive). */
|
|
8
|
+
async function findSectionIslands(sectionDir) {
|
|
9
|
+
const out = [];
|
|
10
|
+
for (const entry of await readdir(sectionDir, { withFileTypes: true })) {
|
|
11
|
+
const full = join(sectionDir, entry.name);
|
|
12
|
+
if (entry.isDirectory()) out.push(...await findSectionIslands(full));
|
|
13
|
+
else if (COMPONENT_EXTS.has(extname(entry.name)) && isClientComponentFile(full)) out.push(full);
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
export { findSectionIslands };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Plugin } from "esbuild";
|
|
2
|
+
//#region src/islands/esbuild-plugin.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Wrap every `"use client"` `.tsx`/`.jsx` in the build graph so it renders through
|
|
5
|
+
* `IslandMarker`, keyed `islandKey(sectionKey, <file-basename>)`. `sectionKey` is
|
|
6
|
+
* fixed per bundle (one section per renderer build). Non-client modules and other
|
|
7
|
+
* extensions fall through to esbuild untouched.
|
|
8
|
+
*/
|
|
9
|
+
declare function islandTransformEsbuildPlugin(opts: {
|
|
10
|
+
sectionKey: string;
|
|
11
|
+
}): Plugin;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { islandTransformEsbuildPlugin };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { islandKey } from "./detect.js";
|
|
2
|
+
import { wrapClientModuleSource } from "./wrap.js";
|
|
3
|
+
import { basename, extname } from "node:path";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
|
|
6
|
+
//#region src/islands/esbuild-plugin.ts
|
|
7
|
+
const LOADER = {
|
|
8
|
+
".tsx": "tsx",
|
|
9
|
+
".jsx": "jsx"
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Wrap every `"use client"` `.tsx`/`.jsx` in the build graph so it renders through
|
|
13
|
+
* `IslandMarker`, keyed `islandKey(sectionKey, <file-basename>)`. `sectionKey` is
|
|
14
|
+
* fixed per bundle (one section per renderer build). Non-client modules and other
|
|
15
|
+
* extensions fall through to esbuild untouched.
|
|
16
|
+
*/
|
|
17
|
+
function islandTransformEsbuildPlugin(opts) {
|
|
18
|
+
return {
|
|
19
|
+
name: "template-kit:island-transform-esbuild",
|
|
20
|
+
setup(b) {
|
|
21
|
+
b.onLoad({ filter: /\.(tsx|jsx)$/ }, async (args) => {
|
|
22
|
+
const code = await readFile(args.path, "utf8");
|
|
23
|
+
const wrapped = wrapClientModuleSource(code, islandKey(opts.sectionKey, basename(args.path, extname(args.path))));
|
|
24
|
+
const ext = extname(args.path);
|
|
25
|
+
if (wrapped === null) return {
|
|
26
|
+
contents: code,
|
|
27
|
+
loader: LOADER[ext]
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
contents: wrapped,
|
|
31
|
+
loader: LOADER[ext]
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
export { islandTransformEsbuildPlugin };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/islands/wrap.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Rewrite a client module's source so its default export renders through
|
|
4
|
+
* `IslandMarker` with `islandKey`. Returns null when `code` is not a client
|
|
5
|
+
* component (`hasClientDirective` false) or has no default export — the caller
|
|
6
|
+
* then leaves the module untouched. The rebound original is `__trIslandReal`;
|
|
7
|
+
* it still flows through the consumer's JSX/TS transform unchanged.
|
|
8
|
+
*/
|
|
9
|
+
declare function wrapClientModuleSource(code: string, islandKey: string): string | null;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { wrapClientModuleSource };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { hasClientDirective } from "../eslint/is-client-file.js";
|
|
2
|
+
import MagicString from "../node_modules/magic-string/dist/magic-string.es.js";
|
|
3
|
+
|
|
4
|
+
//#region src/islands/wrap.ts
|
|
5
|
+
const DEFAULT_EXPORT = /export\s+default\s+/;
|
|
6
|
+
/**
|
|
7
|
+
* The codemod as a `MagicString`, so a caller (the Vite plugin) can emit a
|
|
8
|
+
* hi-res sourcemap alongside the rewritten code. Returns null on the same terms
|
|
9
|
+
* as `wrapClientModuleSource` — a non-client module or one with no default
|
|
10
|
+
* export. The rebound original is `__trIslandReal`; it still flows through the
|
|
11
|
+
* consumer's JSX/TS transform unchanged.
|
|
12
|
+
*/
|
|
13
|
+
function wrapClientModuleMagic(code, islandKey) {
|
|
14
|
+
if (!hasClientDirective(code)) return null;
|
|
15
|
+
if (!DEFAULT_EXPORT.test(code)) return null;
|
|
16
|
+
const s = new MagicString(code);
|
|
17
|
+
s.replace(DEFAULT_EXPORT, "const __trIslandReal = ");
|
|
18
|
+
s.append(wrapperSource(islandKey));
|
|
19
|
+
return s;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Rewrite a client module's source so its default export renders through
|
|
23
|
+
* `IslandMarker` with `islandKey`. Returns null when `code` is not a client
|
|
24
|
+
* component (`hasClientDirective` false) or has no default export — the caller
|
|
25
|
+
* then leaves the module untouched. The rebound original is `__trIslandReal`;
|
|
26
|
+
* it still flows through the consumer's JSX/TS transform unchanged.
|
|
27
|
+
*/
|
|
28
|
+
function wrapClientModuleSource(code, islandKey) {
|
|
29
|
+
return wrapClientModuleMagic(code, islandKey)?.toString() ?? null;
|
|
30
|
+
}
|
|
31
|
+
function wrapperSource(islandKey) {
|
|
32
|
+
return `
|
|
33
|
+
;
|
|
34
|
+
import { createElement as __trCreateElement, useId as __trUseId } from "react";
|
|
35
|
+
import { IslandMarker as __TrIslandMarker } from "@homepages/template-kit";
|
|
36
|
+
export default function __trIslandWrapper(__trProps) {
|
|
37
|
+
const __trIslandId = __trUseId();
|
|
38
|
+
return __trCreateElement(
|
|
39
|
+
__TrIslandMarker,
|
|
40
|
+
{ islandKey: ${JSON.stringify(islandKey)}, islandId: __trIslandId, props: __trProps },
|
|
41
|
+
__trCreateElement(__trIslandReal, __trProps),
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
export { wrapClientModuleMagic, wrapClientModuleSource };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//#region node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
|
|
2
|
+
var comma = ",".charCodeAt(0);
|
|
3
|
+
var semicolon = ";".charCodeAt(0);
|
|
4
|
+
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
5
|
+
var intToChar = /* @__PURE__ */ new Uint8Array(64);
|
|
6
|
+
var charToInt = /* @__PURE__ */ new Uint8Array(128);
|
|
7
|
+
for (let i = 0; i < chars.length; i++) {
|
|
8
|
+
const c = chars.charCodeAt(i);
|
|
9
|
+
intToChar[i] = c;
|
|
10
|
+
charToInt[c] = i;
|
|
11
|
+
}
|
|
12
|
+
function encodeInteger(builder, num, relative) {
|
|
13
|
+
let delta = num - relative;
|
|
14
|
+
delta = delta < 0 ? -delta << 1 | 1 : delta << 1;
|
|
15
|
+
do {
|
|
16
|
+
let clamped = delta & 31;
|
|
17
|
+
delta >>>= 5;
|
|
18
|
+
if (delta > 0) clamped |= 32;
|
|
19
|
+
builder.write(intToChar[clamped]);
|
|
20
|
+
} while (delta > 0);
|
|
21
|
+
return num;
|
|
22
|
+
}
|
|
23
|
+
var bufLength = 1024 * 16;
|
|
24
|
+
var td = typeof TextDecoder !== "undefined" ? /* @__PURE__ */ new TextDecoder() : typeof Buffer !== "undefined" ? { decode(buf) {
|
|
25
|
+
return Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength).toString();
|
|
26
|
+
} } : { decode(buf) {
|
|
27
|
+
let out = "";
|
|
28
|
+
for (let i = 0; i < buf.length; i++) out += String.fromCharCode(buf[i]);
|
|
29
|
+
return out;
|
|
30
|
+
} };
|
|
31
|
+
var StringWriter = class {
|
|
32
|
+
constructor() {
|
|
33
|
+
this.pos = 0;
|
|
34
|
+
this.out = "";
|
|
35
|
+
this.buffer = new Uint8Array(bufLength);
|
|
36
|
+
}
|
|
37
|
+
write(v) {
|
|
38
|
+
const { buffer } = this;
|
|
39
|
+
buffer[this.pos++] = v;
|
|
40
|
+
if (this.pos === bufLength) {
|
|
41
|
+
this.out += td.decode(buffer);
|
|
42
|
+
this.pos = 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
flush() {
|
|
46
|
+
const { buffer, out, pos } = this;
|
|
47
|
+
return pos > 0 ? out + td.decode(buffer.subarray(0, pos)) : out;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
function encode(decoded) {
|
|
51
|
+
const writer = new StringWriter();
|
|
52
|
+
let sourcesIndex = 0;
|
|
53
|
+
let sourceLine = 0;
|
|
54
|
+
let sourceColumn = 0;
|
|
55
|
+
let namesIndex = 0;
|
|
56
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
57
|
+
const line = decoded[i];
|
|
58
|
+
if (i > 0) writer.write(semicolon);
|
|
59
|
+
if (line.length === 0) continue;
|
|
60
|
+
let genColumn = 0;
|
|
61
|
+
for (let j = 0; j < line.length; j++) {
|
|
62
|
+
const segment = line[j];
|
|
63
|
+
if (j > 0) writer.write(comma);
|
|
64
|
+
genColumn = encodeInteger(writer, segment[0], genColumn);
|
|
65
|
+
if (segment.length === 1) continue;
|
|
66
|
+
sourcesIndex = encodeInteger(writer, segment[1], sourcesIndex);
|
|
67
|
+
sourceLine = encodeInteger(writer, segment[2], sourceLine);
|
|
68
|
+
sourceColumn = encodeInteger(writer, segment[3], sourceColumn);
|
|
69
|
+
if (segment.length === 4) continue;
|
|
70
|
+
namesIndex = encodeInteger(writer, segment[4], namesIndex);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return writer.flush();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { encode };
|