create-bascik 1.0.0-rc.1 → 1.0.0-rc.3
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/assets/SKILL.md +147 -18
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/scaffold.d.ts +2 -2
- package/dist/scaffold.js +8 -8
- package/dist/scaffold.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +3 -1
- package/src/index.ts +2 -2
- package/src/scaffold.test.ts +14 -2
- package/src/scaffold.ts +8 -8
package/assets/SKILL.md
CHANGED
|
@@ -28,6 +28,8 @@ This file contains the **complete, centralized documentation and development ski
|
|
|
28
28
|
* It does not add any JavaScript to pages. Every script in the output was written by you.
|
|
29
29
|
* It does not require Web Components, Shadow DOM, or any browser-specific API.
|
|
30
30
|
|
|
31
|
+
**Node version:** Node.js 24 LTS is recommended. The minimum is 22.18, which provides native TypeScript stripping.
|
|
32
|
+
|
|
31
33
|
### End-to-End Example: Input → Output
|
|
32
34
|
|
|
33
35
|
One component file, its usage, and the scoped build output:
|
|
@@ -100,6 +102,12 @@ Because IDs are scoped per instance, the same component can appear multiple time
|
|
|
100
102
|
* Bascik consumes those instructions at build time. They are not runtime directives that require a client library to interpret them.
|
|
101
103
|
* **Tag structure ordering rule:** When writing component files containing both styles and scripts alongside HTML, always place `<style>` tags above the HTML markup as a style guide, and always place `<script>` tags below the HTML markup.
|
|
102
104
|
|
|
105
|
+
### Script Ownership and Decomposition
|
|
106
|
+
* Put page behavior in that page's script and component behavior in that component's script. Prefer a focused inline `<script>` or a same-directory companion `.js`/`.ts` referenced with `<script src="...">` over a page-wide `main.js` that queries and coordinates every component's DOM.
|
|
107
|
+
* Keep scripts small enough that their owning markup and behavior can be understood together. Split unrelated behavior into multiple component scripts rather than accumulating it in one global application script.
|
|
108
|
+
* A shared script is appropriate when it provides genuinely shared code or state, such as one authenticated API client or a third-party library used by several components. Load shared code once, give components a small explicit interface to it, and keep component-specific DOM behavior in the component.
|
|
109
|
+
* Client scripts are not npm bundlers. Bare package imports do not resolve in the browser; see [JavaScript Libraries & Progressive Enhancement](#12-javascript-libraries--progressive-enhancement) for bundling a shared dependency.
|
|
110
|
+
|
|
103
111
|
### Repository Layout and the Create App
|
|
104
112
|
|
|
105
113
|
The repo is split into four top-level folders:
|
|
@@ -278,7 +286,7 @@ Scoped CSS can live in a paired `.css` file or one or more inline `<style>` tags
|
|
|
278
286
|
At build time, Bascik extracts all inline `<style>` blocks, combines them with any companion `.css` file, scopes them, and injects them into the document `<head>`. Using multiple `<style>` tags (or mixing them with a companion `.css` file) is supported but not recommended for readability and maintainability. Choose a single stylesheet pattern per component.
|
|
279
287
|
|
|
280
288
|
### Global Class Passthrough
|
|
281
|
-
Bascik checks whether a class name in a component template is defined in the component's CSS (paired `.css` or inline `<style>`). Only class names defined in the component's stylesheet are scoped (prefixed/hashed). Classes in component HTML that are NOT defined in the component's stylesheet (such as global utility classes like `skip-link`, `flex`, `hidden`, or design system classes) pass through as unscoped global classes so global stylesheets continue to match them.
|
|
289
|
+
Bascik checks whether a class name in a component template is defined in the component's CSS (paired `.css` or inline `<style>`). Only class names defined in the component's stylesheet are scoped (prefixed/hashed). Classes in component HTML that are NOT defined in the component's stylesheet (such as global utility classes like `skip-link`, `flex`, `hidden`, or design system classes) pass through as unscoped global classes so global stylesheets continue to match them. This includes a component with no stylesheet at all, such as a header or footer styled entirely by a global stylesheet: none of its classes are scoped, so it needs no `.css` file or placeholder comment. It also means such a component has no class isolation, so a script querying `.item` in it matches every `.item` on the page; define the class in a stylesheet to scope it.
|
|
282
290
|
|
|
283
291
|
Pair a `.css` file alongside the HTML in a same-named directory:
|
|
284
292
|
|
|
@@ -398,7 +406,7 @@ Define your design tokens once in a global stylesheet, then consume them inside
|
|
|
398
406
|
* `@import`: local file imports (`@import "./file.css"`) are inlined recursively and scoped to the component; remote URLs (`@import "https://..."`) are preserved and hoisted to the top of the compiled stylesheet
|
|
399
407
|
* Standalone attribute selectors (e.g. `[data-state]`): not scoped and can leak globally; anchor with a scoped class: `.card[data-state]`
|
|
400
408
|
* `[id]` selectors: `[id]` and `[id="..."]` attribute selectors in CSS are stripped at compile time because they cannot be scoped without DOM wrapping
|
|
401
|
-
* Compound element selectors:
|
|
409
|
+
* Compound element selectors: every element name in a chain is converted to a scoped class and injected on matching elements in the component's own template, with or without a class anchor (`.card p {}`, `div p {}`, `p + p {}`, `nav a {}`, `ul li * {}` all work); they never reach page markup or a child component's root
|
|
402
410
|
* Element names inside `:is()`, `:where()`, and `:has()` are not converted; use class selectors inside those pseudo-classes instead
|
|
403
411
|
|
|
404
412
|
---
|
|
@@ -729,12 +737,28 @@ If a component template contains multiple root elements, inherited attributes ar
|
|
|
729
737
|
|
|
730
738
|
Inherited class names are not scoped, they are treated as global page-level classes. To disable inheritance, set `scoping.inheritAttributes` to `false` in `bascik.config.ts`.
|
|
731
739
|
|
|
740
|
+
### Styling a Child Component from Its Parent
|
|
741
|
+
A component's CSS applies only to markup written in its own template. A parent's element selector such as `nav a { }` never matches the root element of a child component, so components stay isolated. To style a child's root from the parent, put a class on the child's usage tag and define that class in the parent's CSS. Bascik scopes it to the parent and merges it onto the child root. A class not defined in the parent's CSS passes through unscoped.
|
|
742
|
+
|
|
743
|
+
```html
|
|
744
|
+
<!-- illustrative: site-nav.html (parent) -->
|
|
745
|
+
<nav>
|
|
746
|
+
<nav-link class="item" href="/">Home</nav-link>
|
|
747
|
+
</nav>
|
|
748
|
+
<!-- site-nav.css: .item { padding: 1em 0.5em; } -->
|
|
749
|
+
<!-- nav-link.html (child, root is an anchor): <a><span data-bascik-slot></span></a> -->
|
|
750
|
+
<!-- output: <a class="bascik__site-nav__item" href="/">Home</a> -->
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
The same applies to markup that a build script or slot produces: put the class on each child usage tag.
|
|
754
|
+
|
|
732
755
|
### Internal Masking vs. Preserving Element Contents
|
|
733
756
|
|
|
734
757
|
These two mechanisms serve distinct purposes:
|
|
735
758
|
|
|
736
759
|
* **Internal scanning mask (internal, hardcoded, not configurable):** Bascik temporarily blanks the contents of `<script>`, `<style>`, `<textarea>`, and HTML comments while scanning with regular expressions, so a component tag inside a JavaScript string, style block, or comment is not mistaken for real markup. The mask is discarded immediately after scanning. Authors never interact with or configure this behavior.
|
|
737
|
-
* **Preserve scoping (authoring choice):** Keep scoping enabled by default. Use `scoping.preserve` (default `['code']`) when every matching tag and subtree must keep literal `id`, `name`, and `class` values. Entries are exact tag names or `*` wildcard patterns (for example `vendor-*` preserves every tag whose name starts with `vendor-`); both use the same semantics. Use bare `data-bascik-preserve` for one element and subtree, or list selected attributes such as `data-bascik-preserve="name"`. Nesting only widens. Preserving `name` gives up per-instance radio-group isolation, so reserve it for external form endpoints that require literal field names.
|
|
760
|
+
* **Preserve scoping (authoring choice):** Keep scoping enabled by default. Use `scoping.preserve` (default `['code']`) when every matching tag and subtree must keep literal `id`, `name`, and `class` values. Entries are exact tag names or `*` wildcard patterns (for example `vendor-*` preserves every tag whose name starts with `vendor-`); both use the same semantics. Use bare `data-bascik-preserve` for one element and subtree, or list selected attributes such as `data-bascik-preserve="name"`. Nesting only widens. Preserving `name` gives up per-instance radio-group isolation, so reserve it for external form endpoints that require literal field names. Preserving an `id` also stops reference rewriting inside the preserved region: a link inside a preserved subtree stays literal even if its target is scoped, so a link and its target must be both preserved or both scoped (a scoped link to a preserved target works). Never preserve a skip link to "keep it working"; put the target `id` on the page shell. Preserve does not silence unresolved-tag warnings.
|
|
761
|
+
* **External custom elements (`components.external`):** Hyphenated tags that belong to a browser custom element or library (for example `heading-anchors`) print `Unresolved component tag` on every page and appear in `bascik --check`. List them in `components: { external: ['heading-anchors', 'vendor-*'] }` (exact names or `*` wildcards, case-insensitive) to remove both. It changes diagnostics only: a real component of the same name still expands, scoping is unaffected, and typos stay reported. To use an npm custom element, copy its ready-to-use module into `dist/` with a `phase: 'pre'` exec script (files in `node_modules` are never copied, and bare specifiers in client scripts are not rewritten), load it with `<script type="module" src="/assets/vendor/name.js">`, and declare the tag here. Bundle it with esbuild instead if it imports other packages.
|
|
738
762
|
|
|
739
763
|
### Self-Closing Tags
|
|
740
764
|
Components that do not contain inner slot content should always use self-closing void syntax:
|
|
@@ -804,6 +828,10 @@ Build scripts receive these `process.env` variables:
|
|
|
804
828
|
|
|
805
829
|
These are critical for scripts that generate per-page output. A script using `BASCIK_SOURCE_FILE`, `BASCIK_PAGE_FILE`, or `BASCIK_PAGE_PATH` gets a separate cache entry per page automatically.
|
|
806
830
|
|
|
831
|
+
`BASCIK_ROUTE` may be any size: over 32 KB it is delivered through a temporary file and set before the script runs, so reading `process.env.BASCIK_ROUTE` is unchanged.
|
|
832
|
+
|
|
833
|
+
**Printed directives never run.** Build script output is transpiled again (component tags expand, client scripts run in the browser), but any `data-bascik-build`, `data-bascik-server`, `data-bascik-stream`, or `data-bascik-routes` script in the output is removed with a warning. Write directives only in source files. This is not a sanitizer: HTML from a CMS or API must still go through an allowlist before printing, because its ordinary scripts, handlers, and component tags are kept.
|
|
834
|
+
|
|
807
835
|
### The Fetch-Once Pattern
|
|
808
836
|
|
|
809
837
|
When a data-driven page needs the same data in several places, read or fetch it **once at page level** in a single `data-bascik-build` script, then apply it everywhere on the page. Not once per component instance. The same data object can feed a second script, a JSON payload for client JavaScript, or a component prop, without a second network round trip or file read.
|
|
@@ -893,14 +921,14 @@ Markdown stays comfortable for authors, while the published page stays **vanilla
|
|
|
893
921
|
|
|
894
922
|
The parser emits ordinary HTML, so it can be styled by a global stylesheet or wrapped in a Bascik component. For reusable scoped styles, have the script emit `<markdown-content>${marked(md)}</markdown-content>` and give that component a default slot.
|
|
895
923
|
|
|
896
|
-
Use wrapper
|
|
924
|
+
Use the wrapper class plus `:is()` around element names for generated slot content:
|
|
897
925
|
|
|
898
926
|
```css
|
|
899
|
-
.markdown-content h2 { margin-block: 2.5rem 0.75rem; }
|
|
900
|
-
.markdown-content blockquote { border-left: 4px solid currentColor; }
|
|
927
|
+
.markdown-content :is(h2) { margin-block: 2.5rem 0.75rem; }
|
|
928
|
+
.markdown-content :is(blockquote) { border-left: 4px solid currentColor; }
|
|
901
929
|
```
|
|
902
930
|
|
|
903
|
-
Do not
|
|
931
|
+
Do not write `h2 {}` or `.markdown-content h2 {}` for Markdown passed through a slot. Bascik scopes an element name by adding a class to the matching elements in the component's own template, also after a wrapper class, so slotted headings (plain tags) never match. Names inside `:is()` are left as written; the wrapper class stays scoped and specificity is unchanged.
|
|
904
932
|
|
|
905
933
|
### Page-Aware Scripts
|
|
906
934
|
|
|
@@ -1149,6 +1177,9 @@ export default defineConfig({
|
|
|
1149
1177
|
out: 'dist',
|
|
1150
1178
|
api: 'src/api',
|
|
1151
1179
|
},
|
|
1180
|
+
components: {
|
|
1181
|
+
external: [],
|
|
1182
|
+
},
|
|
1152
1183
|
scoping: {
|
|
1153
1184
|
scriptBlocks: true,
|
|
1154
1185
|
inheritAttributes: true,
|
|
@@ -1181,6 +1212,7 @@ export default defineConfig({
|
|
|
1181
1212
|
watchPaths: [],
|
|
1182
1213
|
exec: [],
|
|
1183
1214
|
workers: false,
|
|
1215
|
+
onExecError: 'warn', // 'warn' | 'error'. Default: 'warn' in dev, 'error' for --build
|
|
1184
1216
|
},
|
|
1185
1217
|
scripts: {
|
|
1186
1218
|
cache: { enabled: true },
|
|
@@ -1238,6 +1270,7 @@ When creating or modifying `bascik.config.ts`:
|
|
|
1238
1270
|
* **Do NOT invent non-existent `pipeline.exec` scripts:** `pipeline.exec` is only for executing existing custom lifecycle script files. If no custom script file exists in the workspace, omit it.
|
|
1239
1271
|
* **Array Replacement in `build`:** Array properties like `pipeline.exec`, `pipeline.watchPaths`, and `assets.inlineStyles` are replaced as atomic values (not concatenated) when specified in `export const build`. When defining `build.pipeline.exec`, include all scripts that should run in production builds.
|
|
1240
1272
|
* **Write artifacts to `dist/`:** Lifecycle scripts must write generated artifacts only to the output directory, never source files or watched paths. Never configure `pipeline.watchPaths` or `pipeline.exec[].watch` for generated outputs. There is no `outputs` option. Exec receives `BASCIK_BUILD`, `BASCIK_PAGES_DIR`, `BASCIK_OUT_DIR`, `BASCIK_BASE`, and `BASCIK_SITE_URL`. Use `pre` for required generated dependencies, not `parallel`.
|
|
1273
|
+
* **Exec failures (`pipeline.onExecError`):** `'warn'` reports a failing script (terminal and browser overlay) and keeps going; `'error'` stops and exits 1. Applies to pre, parallel, and post, at startup and on edits. Default is `'warn'` for the dev server (a typo must not end the session) and `'error'` for `--build` (a failed script must never produce a build that looks successful). Set it explicitly to flip either mode. Page compile errors are unaffected.
|
|
1241
1274
|
* **Source-owned exec phases:** `pipeline.exec[].watch` selects matching scripts after a source edit. One cycle coalesces overlap with pages, components, and `pipeline.watchPaths`: pre finishes before compilation, parallel starts alongside it, post starts after compilation and disk writes. Known source dependents rebuild once; unknown external dependencies conservatively rebuild all pages without rerunning unmatched scripts. Exec-only inputs need no duplicate `pipeline.watchPaths`. Completion never queues another compile or reload. Edits during work are retained; failed paths retry on the next source edit. Pre/compile/post failures discard success reloads. Dev parallel stays nonblocking and reports every failure; build joins parallel and compilation/post before success. Never suppress watched script edits as presumed self-writes. Bascik cannot safely identify source-writing loops. `scripts.importRoot` and `assets.inlineStyles` do not add compilation watches.
|
|
1242
1275
|
* **Stick to recommended defaults without restating them:** Preserve `scoping.deduplicateCss: true`, `scoping.scriptBlocks: true`, and `scoping.inheritAttributes: true` unless specifically instructed otherwise or integrating global utility frameworks like Tailwind CSS. Do not write these values into a config just to preserve them.
|
|
1243
1276
|
* **Set `BASCIK_SITE_URL` for production features:** Provide the site URL via the environment (e.g. `BASCIK_SITE_URL=https://example.com bascik --build`) when page-aware canonical scripts, sitemaps, or `robots.txt` generation are enabled. Never put `siteUrl` in `bascik.config.ts`.
|
|
@@ -1273,6 +1306,7 @@ src/
|
|
|
1273
1306
|
|
|
1274
1307
|
### Static Assets and Subdirectories
|
|
1275
1308
|
* **One Publish Tree:** Put images, fonts, downloads, standalone browser JavaScript, CSS, and other public assets under `directory.pages`. Colocate them with a route or use shared subdirectories such as `src/pages/assets/`. Eligible files copy to `directory.out` with relative structure preserved.
|
|
1309
|
+
* **Source versus generated output:** `directory.pages` and `directory.components` are authored inputs. Do not write generated bundles, compiled scripts, or other build products into `src/`, including `src/pages/assets/`. Write generated public files to `BASCIK_OUT_DIR` (normally `dist/`) from an existing `pipeline.exec` script. Keep generated output out of version control.
|
|
1276
1310
|
* **Project-Specific Exclusions:** `assets.exclude` adds glob exclusions matched relative to `directory.pages`. Keep tests and source-only helpers outside the publish tree.
|
|
1277
1311
|
* **Auto-Minification:** CSS and JS files placed in `src/pages/` are automatically minified by `bascik --build` and `bascik --server`; no config is required. Custom BYOMinifier minifier/transformer functions (e.g. PostCSS/Autoprefixer, LightningCSS, esbuild, terser) can be assigned to `minify.css` and `minify.js` only when a project needs non-default processing.
|
|
1278
1312
|
* **Built-In Deny-List:** Dotfiles, dot-directories, `node_modules`, `.html`, `.ts`, `.mjs`, `.cjs`, `.mts`, `.cts`, `.map`, `.md`, test/spec files, and inlined stylesheets never copy. This deny-list always applies, including when `assets.exclude` is configured.
|
|
@@ -1448,7 +1482,7 @@ While the dev server is active, Bascik watches your file system and incrementall
|
|
|
1448
1482
|
#### 3. Transpilation & Build Errors
|
|
1449
1483
|
Development and production builds handle page failures differently. The dev server logs a failed page, completes boot, continues serving healthy pages, and retries the failed page on the next save. A production `bascik --build` waits for every page job, reports all failures together, and exits nonzero rather than reporting success with missing output.
|
|
1450
1484
|
|
|
1451
|
-
Hard build failures include a missing or unreadable configured pages directory, a page without a non-empty `<body>`, runaway component expansion, output directory creation failure, and page write failure. `ENOENT` write errors are not ignored.
|
|
1485
|
+
Hard build failures include a missing or unreadable configured pages directory, a missing or unreadable components root listed in `directory.components`, a page without a non-empty `<body>`, runaway component expansion, output directory creation failure, and page write failure. `ENOENT` write errors are not ignored. A missing default `src/components/` is not an error: the project has no components until the directory is created.
|
|
1452
1486
|
|
|
1453
1487
|
```terminal
|
|
1454
1488
|
Build failed with 2 page errors:
|
|
@@ -1473,7 +1507,7 @@ Build failed with 2 page errors:
|
|
|
1473
1507
|
```terminal
|
|
1474
1508
|
[bascik] Unresolved component tag in "pages/about.html": <my-mistyped> - no matching component file found. Run `bascik --check` for a full report.
|
|
1475
1509
|
```
|
|
1476
|
-
Use `bascik --check` (or `bascik --check --strict`) as the CI gate for project references and diagnostics.
|
|
1510
|
+
Use `bascik --check` (or `bascik --check --strict`) as the CI gate for project references and diagnostics. Tags that belong to a custom element or library can be declared in `components.external` so neither the warning nor `--check` reports them.
|
|
1477
1511
|
|
|
1478
1512
|
#### 4. Static Analysis (`bascik --check`)
|
|
1479
1513
|
Run `bascik --check` from your project root to validate pages, component files, config, and API route files without starting the dev server or writing any output:
|
|
@@ -1561,6 +1595,8 @@ Add a CDN `<script src>` tag to the page `<head>` or a shared head component. Ba
|
|
|
1561
1595
|
|
|
1562
1596
|
**Bare specifiers do not work in client scripts.** Bascik does not rewrite `import x from 'some-package'` in a `<script type="module">`; the browser receives it verbatim and fails with `Failed to resolve module specifier`. Bare specifiers work only in `data-bascik-build` and `data-bascik-server` scripts, which run in Node.js. For an npm package with no CDN build, bundle it with esbuild as a `pipeline.exec` step (`phase: 'pre'`), write the bundle into `dist/assets/js/`, and import it from the page with a root-relative URL.
|
|
1563
1597
|
|
|
1598
|
+
The bundler entrypoint should contain only code that is genuinely shared, such as a third-party library bundle or shared runtime state. Keep page- and component-specific behavior in that page's or component's own script; do not move all UI logic into one large bundled entrypoint just to import an npm dependency.
|
|
1599
|
+
|
|
1564
1600
|
```html
|
|
1565
1601
|
<head>
|
|
1566
1602
|
<script src="https://unpkg.com/petite-vue" defer init></script>
|
|
@@ -1816,7 +1852,7 @@ async function walk(dir: string, ext: string): Promise<string[]> {
|
|
|
1816
1852
|
return out;
|
|
1817
1853
|
}
|
|
1818
1854
|
|
|
1819
|
-
describe('dist HTML
|
|
1855
|
+
describe('dist HTML: WHATWG spec compliance', () => {
|
|
1820
1856
|
it('every page is free of parse errors', async () => {
|
|
1821
1857
|
const files = await walk(DIST_DIR, '.html');
|
|
1822
1858
|
const failures: string[] = [];
|
|
@@ -1833,7 +1869,7 @@ describe('dist HTML — WHATWG spec compliance', () => {
|
|
|
1833
1869
|
});
|
|
1834
1870
|
```
|
|
1835
1871
|
|
|
1836
|
-
Run after `bascik --build`. Catches corrupted script bodies, mismatched tags, and unreplaced internal tokens that string-based assertions miss. Bascik is a build tool
|
|
1872
|
+
Run after `bascik --build`. Catches corrupted script bodies, mismatched tags, and unreplaced internal tokens that string-based assertions miss. Bascik is a build tool, so hold output to the full spec, not browser recovery behavior.
|
|
1837
1873
|
|
|
1838
1874
|
### Testing Site Logic in a Bascik Project
|
|
1839
1875
|
|
|
@@ -1938,8 +1974,66 @@ Detailed per-framework migration guides live at `/switch/*`. Key patterns that a
|
|
|
1938
1974
|
- **Slots:** `<slot />` / `children` → `data-bascik-slot` (no value) for default, `data-bascik-slot="name"` for named slots.
|
|
1939
1975
|
- **Props:** `defineProps` / component props → `data-bascik-prop-*` attributes (text only).
|
|
1940
1976
|
- **Reactive state:** `ref`, `useState`, etc. → plain `<script>` with vanilla JS. Bascik scopes `id` values so multiple instances stay independent.
|
|
1941
|
-
- **Routing:** Client-side router → one `.html` file per URL in `src/pages/`.
|
|
1977
|
+
- **Routing:** Client-side router → one `.html` file per URL in `src/pages/`. For parameterized routes (`[slug].astro`, `getStaticPaths`, Eleventy pagination), use a dynamic route template such as `src/pages/blog/[slug]/index.html` (trailing-slash URLs) with a `<script data-bascik-routes>` block. Do not generate page files into `src/pages/`. A route param cannot contain `/`; use one template per depth.
|
|
1942
1978
|
- **Build-time data:** `onMounted` / `getStaticProps` / frontmatter → `<script data-bascik-build>` (Node.js ESM, stdout injected).
|
|
1979
|
+
- **Content collections (Astro `getCollection`, Eleventy `collections`):** No built-in equivalent. Write a `src/lib/posts.ts` helper that reads `content/` with `fs`, parses front matter with `gray-matter`, validates with `zod`, and sorts by the parsed date (not the file name). Escape every interpolated value. Drafts: skip them when `process.env.BASCIK_BUILD === '1'`. Exclude scripts that read `content/` from `scripts.cache` and add `content/` to `pipeline.watchPaths`.
|
|
1980
|
+
- **Template logic (Nunjucks/Liquid loops, filters, includes with variables):** Becomes TypeScript helpers in `src/lib/` that return HTML. Only static includes become components. Pages keep `<html>`/`<head>`/`<body>`; a component cannot own them.
|
|
1981
|
+
- **Feeds, sitemaps, images:** RSS/Atom is a `pipeline.exec` script (`phase: 'post'`) writing to `BASCIK_OUT_DIR`. Sitemap and robots are built in. No image optimization or syntax highlighting built in; do it in your own build step.
|
|
1982
|
+
- **Component scripts that print styled markup:** Output of a component build script, page-aware or not, is scoped like the template, including markup returned by imported helpers. Classes the component stylesheet does not define stay global.
|
|
1983
|
+
|
|
1984
|
+
### From React
|
|
1985
|
+
|
|
1986
|
+
Full guide: `/switch/from-react`. Key React-specific mappings:
|
|
1987
|
+
|
|
1988
|
+
| React | Bascik |
|
|
1989
|
+
|-------|--------|
|
|
1990
|
+
| Function component | `.html` file in `src/components/<name>/`, folder name is the hyphenated tag |
|
|
1991
|
+
| `children` | `data-bascik-slot` (no value), fallback inside it |
|
|
1992
|
+
| Render prop / named children | `<div data-bascik-slot="x">` wrapper at the usage site and in the component |
|
|
1993
|
+
| `props.x` | `data-bascik-prop-x` (text only; booleans and numbers arrive as strings) |
|
|
1994
|
+
| Prop used as an attribute | `data-bascik-attr-<attribute>="propName"` |
|
|
1995
|
+
| Object, array, or function prop | Not possible. Print one component per item from a build script; use a bubbling `CustomEvent` instead of a callback |
|
|
1996
|
+
| `useState` in the common parent | Variables in the parent component's `<script>`; a function applies them to the DOM |
|
|
1997
|
+
| `onChange` callback prop | Child dispatches `new CustomEvent('x', { bubbles: true, detail })` from its own element; the parent listens on its root |
|
|
1998
|
+
| Re-render of a filtered list | One function sets `hidden` on existing rows; there is no diff, so write every place a value shows |
|
|
1999
|
+
| `.map()` over data | `<script data-bascik-build>` that prints component tags with escaped props |
|
|
2000
|
+
| Conditional style | A `data-` attribute and a CSS selector, in the component's own CSS |
|
|
2001
|
+
| React Router `/blog/:slug` | `src/pages/blog/[slug]/index.html` with `<script data-bascik-routes>` |
|
|
2002
|
+
|
|
2003
|
+
React-specific gotchas:
|
|
2004
|
+
|
|
2005
|
+
- **Escape every interpolated value in a build script.** JSX does it for you; a template string does not.
|
|
2006
|
+
- **Forwarding `children` to an inner component:** write a default slot marker between the inner component's tags, `<inner-box><div data-bascik-slot>fallback</div></inner-box>`. It receives the outer usage's default content. Named wrappers between the inner tags fill the inner component's named slots.
|
|
2007
|
+
- **Plain inputs can disagree with state after Back or reload.** Report the fields again on `pageshow`. A form with one text box submits on Enter; call `preventDefault()` in a `submit` listener when a script drives the form.
|
|
2008
|
+
- **Component scripts run once and are moved in production.** Minified production HTML moves them to the end of the document; the dev server leaves them in place. Look up elements inside handlers or after `DOMContentLoaded`.
|
|
2009
|
+
- **`bascik --check` cannot see a component that only a build script prints** and reports it as unused.
|
|
2010
|
+
- **Tag names need a hyphen.** `Card.jsx` becomes `info-card`.
|
|
2011
|
+
|
|
2012
|
+
### From Next.js
|
|
2013
|
+
|
|
2014
|
+
Full guide: `/switch/from-next`. Key Next.js-specific mappings:
|
|
2015
|
+
|
|
2016
|
+
| Next.js | Bascik |
|
|
2017
|
+
|---------|--------|
|
|
2018
|
+
| `app/page.tsx`, `app/posts/[slug]/page.tsx` | `src/pages/index.html`, `src/pages/posts/[slug].html` (`/posts/<slug>`, also served with a trailing slash) |
|
|
2019
|
+
| `generateStaticParams` | `<script data-bascik-routes>` printing `[{ "params": { "slug": "..." } }]` |
|
|
2020
|
+
| `generateMetadata` / `metadata` export | A build script in `<head>` that prints `<title>` and `<meta>` from a `src/lib` helper; absolute URLs from `BASCIK_SITE_URL` |
|
|
2021
|
+
| `app/layout.tsx` | Pages keep `<html>`/`<head>`/`<body>`; a head component plus header/footer components |
|
|
2022
|
+
| Server component that maps data to JSX | A `src/lib` helper returning escaped HTML strings, printed by a build script |
|
|
2023
|
+
| `"use client"` component with `useState`/`useEffect` | A component with a plain `<script>`; persistent state lives in the DOM or `localStorage` |
|
|
2024
|
+
| `next/link`, `next/image`, `next/font` | `<a>`, `<img>` with `width`/`height`, a self-hosted `@font-face` plus `<link rel="preload">` |
|
|
2025
|
+
| CSS Modules (`styles.x`) | Paired component `.css`; a class written in the template is scoped |
|
|
2026
|
+
| Tailwind via PostCSS | A `pipeline.exec` `pre` script running PostCSS + Tailwind into `BASCIK_OUT_DIR`; Tailwind `content` lists `src/**/*.html` and `src/lib/**/*.ts` |
|
|
2027
|
+
| `app/api/x/route.ts` | `src/api/x.ts` exporting `GET`/`POST`; `context.params` is a plain object, not a promise; `bascik --server` only |
|
|
2028
|
+
|
|
2029
|
+
Next.js-specific gotchas:
|
|
2030
|
+
|
|
2031
|
+
- **`@/` in a helper that imports a helper fails.** tsconfig `paths` do not apply; Node runs `src/lib/*.ts` directly. Inside helpers use relative paths with the `.ts` extension, and `import type` for type-only imports.
|
|
2032
|
+
- **Tailwind `@apply` in component CSS is not processed.** Write the CSS out, or keep `@apply` in the global Tailwind input file.
|
|
2033
|
+
- **Tailwind's `dark` class works unscoped** when it is toggled on `<html>` and the component's own CSS does not define it.
|
|
2034
|
+
- **A pre-paint script (theme, FOUC) goes in `<head>`.** Production HTML minification moves body scripts to the end of the body; head scripts stay put.
|
|
2035
|
+
- **Style slotted Markdown with `.wrapper :is(h2)`**, not `.wrapper h2` (see Markdown above).
|
|
2036
|
+
- **Unknown slugs return 404.** The upstream example answers 500 for them, because `getPostBySlug` throws before `notFound()`.
|
|
1943
2037
|
|
|
1944
2038
|
### From Svelte
|
|
1945
2039
|
|
|
@@ -1966,12 +2060,47 @@ Full guide: `/switch/from-vue`. Key Vue-specific mappings:
|
|
|
1966
2060
|
|-----|--------|
|
|
1967
2061
|
| `<template>` + `<style scoped>` | `.html` + `.css` paired files |
|
|
1968
2062
|
| `<slot />` | `data-bascik-slot` (no value) |
|
|
1969
|
-
| `<slot name="x" />` |
|
|
1970
|
-
| `defineProps` | `data-bascik-prop-*` attributes |
|
|
1971
|
-
|
|
|
1972
|
-
|
|
|
1973
|
-
| `
|
|
1974
|
-
| `
|
|
2063
|
+
| `<slot name="x" />` / `<template #x>` | `<div data-bascik-slot="x">` wrapper around the content, in the component and at the usage site |
|
|
2064
|
+
| `defineProps` | `data-bascik-prop-*` attributes (text only) |
|
|
2065
|
+
| Array or object prop (`:data="rows"`) | JSON in a `<script type="application/json">` that fills the default slot; a build script prints it from a `src/lib` helper, and `<` is escaped as `\u003c` |
|
|
2066
|
+
| `$emit`, `v-model` | DOM events: `dispatchEvent(new CustomEvent(...))` and `addEventListener` |
|
|
2067
|
+
| `ref` / `reactive` | Vanilla JS `<script>`; the script updates the DOM itself |
|
|
2068
|
+
| `v-if` / `v-show` | Build-time: a build script prints one branch. Runtime: toggle the `hidden` attribute |
|
|
2069
|
+
| `v-for` | Build-time loop in a build script, or clone a `<template>` from a script |
|
|
2070
|
+
| `vue-router` | One `.html` per route in `src/pages/`; parameterized routes use `src/pages/blog/[slug].html` with `<script data-bascik-routes>` |
|
|
2071
|
+
| `onMounted` data fetch | `<script data-bascik-build>` for data that is the same for everyone, `fetch()` in a component script otherwise |
|
|
2072
|
+
|
|
2073
|
+
Vue-specific gotchas:
|
|
2074
|
+
|
|
2075
|
+
- **Named-slot wrappers are removed.** `<h1 data-bascik-slot="header">Title</h1>` at the usage site produces `Title` with no `<h1>` (an `<a>` loses its `href` too). Write `<div data-bascik-slot="header"><h1>Title</h1></div>`.
|
|
2076
|
+
- **Component tag names need a hyphen.** `Card.vue` becomes `info-card`; a tag named `card` warns.
|
|
2077
|
+
- **Script-created elements get no element-selector styles.** CSS such as `td { }` applies to template markup. Put the markup in a `<template>` inside the component and clone it, instead of `document.createElement('td')`.
|
|
2078
|
+
- **Script placement differs between modes.** Production HTML minification moves component scripts to the end of the document; the development server and `minify.html: false` leave them in place. Never rely on a later element existing when the script starts: look it up inside an event handler or after `DOMContentLoaded`. Use `pageshow` to resync a form value the browser restored on Back.
|
|
2079
|
+
- **`bascik --check` cannot see a component that only a build script prints** and reports it as unused.
|
|
2080
|
+
|
|
2081
|
+
### From WordPress
|
|
2082
|
+
|
|
2083
|
+
Full guide: `/switch/from-wordpress`. Key WordPress-specific mappings:
|
|
2084
|
+
|
|
2085
|
+
| WordPress | Bascik |
|
|
2086
|
+
|-----------|--------|
|
|
2087
|
+
| The Loop, `WP_Query` | A `src/lib` helper returning escaped HTML, printed by a build script |
|
|
2088
|
+
| `single.php` at `/%year%/%monthnum%/%day%/%postname%/` | `src/pages/[year]/[month]/[day]/[slug]/index.html` (one bracket per segment; a param cannot contain `/`) |
|
|
2089
|
+
| Pages and child pages | `src/pages/[pageslug]/index.html` and `src/pages/[parent]/[child]/index.html` |
|
|
2090
|
+
| Category, tag, and `/page/2/` archives | `category/[term]/`, `tag/[term]/`, `page/[page]/` templates, each paged archive its own template |
|
|
2091
|
+
| REST API (`/wp-json/wp/v2/`) | One `pre` exec script fetches everything (follow `X-WP-TotalPages`; `per_page` above 100 is a 400), sanitizes it, downloads media into `BASCIK_OUT_DIR`, and writes a JSON snapshot pages read |
|
|
2092
|
+
| Tools > Export (WXR) | `wordpress-export-to-markdown`, then restore page parents, menu order, term names, and image alt text by hand |
|
|
2093
|
+
| `wp-content/uploads/` | Same path under `dist/`, so content URLs keep working |
|
|
2094
|
+
| `/feed/` | A `post` exec script writing `/feed.xml`; redirect `/feed/` on the host |
|
|
2095
|
+
|
|
2096
|
+
WordPress-specific gotchas:
|
|
2097
|
+
|
|
2098
|
+
- **Sanitize every post body before printing it.** `content.rendered` can hold `<script>`, `on*` handlers, and `javascript:` links; administrators may save any markup. Use an allowlist such as `sanitize-html`, which also drops custom elements so content cannot place a component tag. Bascik itself only removes printed directive scripts.
|
|
2099
|
+
- **Exclude pages that read fetched data from the script cache** (`scripts.cache.exclude`). Network responses are not part of the cache key, so a rebuild after an edit in WordPress otherwise reuses old output.
|
|
2100
|
+
- **Keep page helpers light.** Every build script is its own Node process; import `zod` and `sanitize-html` in the sync step, not in helpers every page loads.
|
|
2101
|
+
- **Raise the exec `timeout` for media downloads.** The default is 60 seconds.
|
|
2102
|
+
- **Titles are HTML over REST** (`&`, curly quotes); convert to text, then escape. WXR titles are the raw text.
|
|
2103
|
+
- **No comments, search, or date and author archives** in a static build; use services or add templates.
|
|
1975
2104
|
|
|
1976
2105
|
### Migrating Existing Sitemap & Robots Files
|
|
1977
2106
|
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QACtD,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;QACpC,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;KAC7C,CAAC;AACJ,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { join } from "node:path";
|
|
|
5
5
|
import { parseCliOptions } from "./cli.js";
|
|
6
6
|
import { scaffold, validateProjectName } from "./scaffold.js";
|
|
7
7
|
const args = process.argv.slice(2);
|
|
8
|
-
const { yesFlag, noDevFlag } = parseCliOptions(args);
|
|
8
|
+
const { yesFlag, noDevFlag, noInstallFlag } = parseCliOptions(args);
|
|
9
9
|
const nameArg = args.find((a) => !a.startsWith("-"));
|
|
10
10
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
11
11
|
let projectName;
|
|
@@ -28,7 +28,7 @@ console.log(`✓ Scaffolded ${projectName}/\n`);
|
|
|
28
28
|
let shouldInstall;
|
|
29
29
|
let shouldDev;
|
|
30
30
|
if (yesFlag) {
|
|
31
|
-
shouldInstall =
|
|
31
|
+
shouldInstall = !noInstallFlag;
|
|
32
32
|
shouldDev = !noDevFlag;
|
|
33
33
|
}
|
|
34
34
|
else {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAE9D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/scaffold.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export declare const FAVICON_SVG = "<svg viewBox=\"0 0 32 32\" width=\"32\" heig
|
|
|
16
16
|
export declare const FAVICON_ICO_B64 = "AAABAAMAEBAAAAEAIADIAAAANgAAACAgAAABACAACAEAAP4AAAAwMAAAAQAgAGcBAAAGAgAiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAeklEQVQ4jWNgoDa4/L93/uX/vf8J4577OAzouU+cAb3zMTSf/9+vQKTm/xf/9yRgGHDxf08CsqINV8vBGJsBIMsI+r+g3Q+MyfZ/AU4DiPR/AQ4DiPL/ZTwGEOX/yzgNICH+C7C7gPj434AlGon2/2UcmGj/0y/9UwoAAEX+8tkvEHwAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAAJcEhZcwAACxMAAAsTAQCanBgAAAC6SURBVFiF7ZbRDYMwDEQzwcEIDFC6QJXf0jEYKBEjMBJCGYBRXNEFepZshaqx5O+8+HQ+h9DqS22yDEWy2HY6Alu7pNkeIK80QJG8WgOcn1IApMMa4JSVenxr+svF9X88bxKnsZ7+6PpPV/M/1ADG/ocSwNz/UAKY+x8qAIf9D90E7Pc/FAAu+x8KAJf9DxrAKf/BT8An/0ECuOU/SAC3/I/TKPF1r6N/4bvdf4OL/oXqpn/6kfv/r+sNLlrC+A4T1ksAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAMAAAADAIBgAAAFcC+YcAAAAJcEhZcwAACxMAAAsTAQCanBgAAAEZSURBVGiB7ZjBDcJADARTAVBCKKKGSwfpgo+PlHDfQDOWSQGpBIwuD/7EVpYIr2Qpr+hGXln2Nk0otL0mzWXSrJii2QGAZhxALqbHsw4t8PEqSskEUH+ABGAdWhNA+F/D/+sV/teY/9vNf3mS0piWerxof/OfxqSH42mpfOv2N//7y/kDUL935//eFSBvv/94Aghi//EEYMT+4wdAmP3fsQMFsv97AQhq//cCYNT+7wNAuPvXqQMFdv96AAjy/vUAYOT9awcgAANi40iAAAn3/00EAB2U7f56m/2eQf30E14yR/0AAAABJRU5ErkJggg==";
|
|
17
17
|
export declare const FAVICON_32_PNG_B64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAuklEQVRYhe2W0Q2DMAxEM8HBCAxQukCV39IxGCgRIzASQhmAUVzRBXqWbIWqseTvvPh0PofQ6kttsgxFsth2OgJbu6TZHiCvNECRvFoDnJ9SAKTDGuCUlXp8a/rLxfV/PG8Sp7Ge/uj6T1fzP9QAxv6HEsDc/1ACmPsfKgCH/Q/dBOz3PxQALvsfCgCX/Q8awCn/wU/AJ/9BArjlP0gAt/yP0yjxda+jf+G73X+Di/6F6qZ/+pH7/6/rDS5awvgOE9ZLAAAAAElFTkSuQmCC";
|
|
18
18
|
export declare const APPLE_TOUCH_ICON_PNG_B64 = "iVBORw0KGgoAAAANSUhEUgAAALQAAAC0CAYAAAA9zQYyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGKUlEQVR4nO2bzWqdVRSGN72AtqO0WicWJ1KtoTi0dGjTK8gFGGtnH1ghJpXOw1l0kHoTUvlIU6rQa9Dg2R9W8OcK2guwky0nkIGU0kTfsvZZ63nhnWWwz7ufnTwcSCmEEEIIIYQQQgghhBBCCCGEEEII6SG12Xptsyd0Fm2DrZIxtdlYmzVq0TYYSra0dvfUvM2edTA+bdoNpnZvtWTL4kMDU7zHNG+z54tfViVbFn+WvMen9iY2GEvG4M9hH9RQsgV/jtsJf/a/BGqSDfBnYGrBNsCfO7gE2mQb4M8AZWE2wJ87uARqkg3wZ2CK9pjGkjF8/xy2Q8kWvn+O24nvn/0vgZpkA/wZmKI9prFkDP4ctkPJFvw5bif82f8SqEk2wJ+BKdpjGkvG4M9hO5RswZ/jdsKf/S+BmmQD/BmYoj2msWQM/hy2Q8kW/DluJ/zZ/xKoSTbAn4Ep2mMaS8bgz2E7lGzBn+N2wp/9L4GaZAP8GZiiPaaxZAz+HLZDyRb8OW4n/Nn/EqhJNsCfgSnaYxpLxuDPYTuUbMGf43bCn5evj3/farsPNw77+I9t9/PUToo/L1n3ft1sn3z6YTt95uy/evX65bb3dNP9fNW/+POy9Lufvmzn3l55Ceajnr+w0h4c3HY/Z/Ut/rwM/fnvnfb+6ruvhPmol65cbAcvdtzPW52KPy9Jd/c+ey3MR72/v+F+3upQ/HmJenN77dhAf3Fnzf281af487J0/da1YwO9+Fnv81af4s8dXAJAN81G+HMHoAK0SfbBnzuAFKBNuRH+7A0pQJtyI/zZG1KANtk++HMHkAK0SbbBnzsAFKBNuQ/+7A0oQJtyH/zZG1CANtk2+HMHgAK0SXbBnzuAE6BNuQ3+7A0nQJtyG/zZG04ANtku+HMHcAK0STbBnzsAE6BNuQv+7A0mQJtyF/zZG0yANtkm+HMHYAK0SfbAnzuAEqBNuQn+7A0lQJtyE/zZG0qANtke+HMHUAK0SbbAnzsAEgBNuQf+7A0kQJtyD/zZG0iANtkW+HMHQAK0SXbAnzuAEaBNuQX+7A0jQJtyC/zZG0aANtkO+HMHMAK0STbAnzsAEQBNuQP+7A0iQJtyB/zZG0SANtkG+HMHIAK0ZgP8uQMIAdqUG+DP3hACtCk3wJ+9IQRok22AP3cAIUCbZAP8uQMAAdqUG+DP3gACtCk3wJ+9AQRok22AP3cAIECbZAP8uQP4ANqUG+DP3vABtCk3wJ+94QNok22AP3cAH0CbZAP8uQPwANqUG+DP3uABtCk3wJ+9wQNok22AP3cAHkCbZAP8uQPoANqUG+DP3tABtCk3wJ+9oQNok22AP3cAHUCbZAP8uQPgANqUG+DP3sABtCk3wJ+9gQNok22AP3cAHECbZAP8uQPYANqUG+DP3rABtCk3wJ+9YQNok22AP3cAG0CbZAP8uQPQANqUG+DP3qABtCk3wJ+9QQNok22AP3cAGkCbZAP8uQPIANqUG+DPmXpze62dPnP2WL31zQ3389aTF3/O1N2HG8cG+ttHn7uft56w+HOyHrzYaZeuXHwtzB98/N7hz3qft56g+HPSPji43c5fWHklzG+9c659/8tX7uesJy/+nLV7Tzfb1euXX4L52o2P2v5vX7ufr/634s/Z+8Of2+3+/sZhf/zrjvt56v8o/tzBJVCTbIA/A1O0xzSWjFl88A7Gp02+Af4MWHEe1tTurZZsWXxo7+GpyTfAnwEr2sMaS8bgz2E7lGxp7e6peZs962B82rQb4M9AFeZRzdvs+eKXVcmWxZ8l7/GpvYnW/d2iwC0CBAgAIAAAAAAAAgAAAAAAQIECBAgAIAAAAAAAAgAAAAAAQIECBAgAIAAAAAAAAgAAAAAAQIECBAgAIAAAAAAAAgAAAAAAQIEC";
|
|
19
|
-
/** Head component
|
|
19
|
+
/** Head component: charset, viewport, favicon, CSS link. */
|
|
20
20
|
export declare const SITE_META_HTML = "<meta charset=\"UTF-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n<meta name=\"description\" content=\"A fast, modern website built with Bascik.\" />\n<link rel=\"icon\" href=\"/favicon.ico\" sizes=\"any\" />\n<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/assets/favicon-32x32.png\" />\n<link rel=\"icon\" type=\"image/svg+xml\" href=\"/assets/favicon.svg\" />\n<link rel=\"apple-touch-icon\" href=\"/assets/apple-touch-icon.png\" />\n<link rel=\"stylesheet\" href=\"/css/styles.css\" />\n";
|
|
21
21
|
export declare const SITE_HEADER_CSS = ".header {\n position: sticky;\n top: 0;\n z-index: 100;\n background: rgba(24, 25, 27, 0.9);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n border-bottom: 1px solid var(--border);\n}\n\n.container { max-width: 1140px; margin: 0 auto; padding: 0 28px; }\n\n.nav {\n display: flex;\n align-items: center;\n height: 60px;\n gap: 24px;\n}\n\n.logo {\n font-weight: 700;\n font-size: 1rem;\n color: var(--text);\n letter-spacing: -0.01em;\n flex-shrink: 0;\n}\n.logo:hover { opacity: 0.8; }\n\n.nav-menu {\n list-style: none;\n margin: 0 0 0 auto;\n padding: 0;\n display: flex;\n gap: 4px;\n}\n.nav-menu a {\n display: block;\n padding: 6px 12px;\n font-size: 0.9rem;\n color: var(--text-muted);\n border-radius: var(--r-sm);\n transition: color .15s, background .15s;\n}\n.nav-menu a:hover { color: var(--text); background: var(--elevated); opacity: 1; }\n\n.nav-toggle {\n display: none;\n flex-direction: column;\n justify-content: center;\n gap: 5px;\n width: 36px;\n height: 36px;\n background: none;\n border: none;\n cursor: pointer;\n padding: 6px;\n margin-left: auto;\n border-radius: var(--r-sm);\n}\n.nav-toggle span {\n display: block;\n height: 2px;\n background: var(--text);\n border-radius: 2px;\n}\n\n@media (max-width: 640px) {\n .nav-toggle { display: flex; }\n\n .nav-menu {\n display: none;\n position: absolute;\n top: 60px;\n left: 0;\n right: 0;\n flex-direction: column;\n gap: 0;\n background: var(--surface);\n border-bottom: 1px solid var(--border);\n padding: 8px 16px;\n }\n .nav-menu.is-open { display: flex; }\n .nav-menu li { width: 100%; }\n .nav-menu a { padding: 10px 4px; }\n}\n";
|
|
22
22
|
/** Sticky top nav with logo (brand prop) and mobile hamburger. */
|
|
@@ -31,7 +31,7 @@ export declare const FEAT_CARD_CSS = ".fcard {\n background: var(--elevated);\n
|
|
|
31
31
|
*/
|
|
32
32
|
export declare const FEAT_CARD_HTML = "<style>\n.fcard {\n background: var(--elevated);\n border: 1px solid var(--border);\n border-radius: var(--r);\n padding: 24px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n transition: border-color .2s, box-shadow .2s, transform .2s;\n}\n.fcard:hover {\n border-color: var(--border-hover);\n box-shadow: 0 0 0 1px var(--accent-dim), 0 8px 32px rgba(0,0,0,0.3);\n transform: translateY(-2px);\n}\n\n.fcard-header {\n font-size: 0.7rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: .1em;\n color: var(--accent);\n}\n.fcard-header:empty { display: none; }\n\n.fcard-body { flex: 1; }\n.fcard-body h3 { margin: 0 0 6px; font-size: 1rem; color: var(--text); }\n.fcard-body p { margin: 0; font-size: 0.88rem; color: var(--text-muted); }\n\n.fcard-footer {\n padding-top: 12px;\n border-top: 1px solid var(--border);\n margin-top: auto;\n}\n.fcard-footer:empty { display: none; }\n</style>\n<article class=\"fcard\">\n <div class=\"fcard-header\" data-bascik-slot=\"header\"></div>\n <div class=\"fcard-body\" data-bascik-slot></div>\n <div class=\"fcard-footer\" data-bascik-slot=\"footer\"></div>\n</article>\n";
|
|
33
33
|
export declare const MY_COUNTER_CSS = ".counter {\n display: inline-flex;\n align-items: center;\n gap: 16px;\n font-size: 1.25rem;\n}\n\n.count-val {\n font-family: var(--mono);\n font-size: 1.5rem;\n min-width: 2ch;\n text-align: center;\n color: var(--accent);\n}\n\n.btn {\n display: inline-flex; align-items: center; gap: 8px;\n padding: 10px 22px; border: none; border-radius: var(--r-sm);\n font-size: 0.9rem; font-weight: 600; cursor: pointer;\n text-decoration: none; transition: filter .15s, opacity .15s; line-height: 1;\n}\n.btn-primary { background: var(--accent); color: #18191b; }\n.btn-ghost { background: transparent; color: var(--text); border: 1px solid var(--border); }\n@media (hover: hover) {\n .btn-primary:hover { filter: brightness(0.88); opacity: 1; }\n .btn-ghost:hover { border-color: var(--accent); color: var(--accent); opacity: 1; }\n}\n";
|
|
34
|
-
/** Interactive counter
|
|
34
|
+
/** Interactive counter: two instances on a page stay fully independent. */
|
|
35
35
|
export declare const MY_COUNTER_HTML = "<style>\n.counter {\n display: inline-flex;\n align-items: center;\n gap: 16px;\n font-size: 1.25rem;\n}\n\n.count-val {\n font-family: var(--mono);\n font-size: 1.5rem;\n min-width: 2ch;\n text-align: center;\n color: var(--accent);\n}\n\n.btn {\n display: inline-flex; align-items: center; gap: 8px;\n padding: 10px 22px; border: none; border-radius: var(--r-sm);\n font-size: 0.9rem; font-weight: 600; cursor: pointer;\n text-decoration: none; transition: filter .15s, opacity .15s; line-height: 1;\n}\n.btn-primary { background: var(--accent); color: #18191b; }\n.btn-ghost { background: transparent; color: var(--text); border: 1px solid var(--border); }\n@media (hover: hover) {\n .btn-primary:hover { filter: brightness(0.88); opacity: 1; }\n .btn-ghost:hover { border-color: var(--accent); color: var(--accent); opacity: 1; }\n}\n</style>\n<div class=\"counter\">\n <button id=\"btn-dec\" class=\"btn btn-ghost\" data-testid=\"counter-dec\">\u2212</button>\n <span id=\"count-val\" class=\"count-val\" data-testid=\"counter-val\">0</span>\n <button id=\"btn-inc\" class=\"btn btn-primary\" data-testid=\"counter-inc\">+</button>\n</div>\n<script>\n (function () {\n var count = 0;\n var val = document.getElementById('count-val');\n document.getElementById('btn-dec').addEventListener('click', function () {\n val.textContent = --count;\n });\n document.getElementById('btn-inc').addEventListener('click', function () {\n val.textContent = ++count;\n });\n }());\n</script>\n";
|
|
36
36
|
export declare const SITE_META_TEST = "import { describe, it, expect } from 'vitest';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\ndescribe('site-meta component', () => {\n const path = join(process.cwd(), 'src/components/site-meta/site-meta.html');\n\n it('contains charset, viewport, favicon, and stylesheet link tags', async () => {\n const html = await readFile(path, 'utf8');\n expect(html).toContain('charset=\"UTF-8\"');\n expect(html).toContain('name=\"viewport\"');\n expect(html).toContain('name=\"description\"');\n expect(html).toContain('favicon.ico');\n expect(html).toContain('favicon-32x32.png');\n expect(html).toContain('favicon.svg');\n expect(html).toContain('apple-touch-icon.png');\n expect(html).toContain('styles.css');\n });\n});\n";
|
|
37
37
|
export declare const SITE_HEADER_TEST = "import { describe, it, expect } from 'vitest';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\ndescribe('site-header component', () => {\n const path = join(process.cwd(), 'src/components/site-header/site-header.html');\n\n it('renders brand prop placeholder and navigation links', async () => {\n const html = await readFile(path, 'utf8');\n expect(html).toContain('data-bascik-prop-brand');\n expect(html).toContain('href=\"/\"');\n expect(html).toContain('href=\"/about\"');\n expect(html).toContain('href=\"/contact\"');\n expect(html).toContain('id=\"nav-toggle\"');\n });\n});\n";
|
package/dist/scaffold.js
CHANGED
|
@@ -26,7 +26,7 @@ export const PACKAGE_JSON = (name) => JSON.stringify({
|
|
|
26
26
|
e2e: "playwright test --config e2e/playwright.config.ts",
|
|
27
27
|
},
|
|
28
28
|
dependencies: {
|
|
29
|
-
"@bascik/bascik": "^1.0.0-rc.
|
|
29
|
+
"@bascik/bascik": "^1.0.0-rc.3",
|
|
30
30
|
},
|
|
31
31
|
devDependencies: {
|
|
32
32
|
"@bascik/language-server": "^0.1.0-rc.1",
|
|
@@ -294,7 +294,7 @@ export const FAVICON_SVG = `<svg viewBox="0 0 32 32" width="32" height="32" xmln
|
|
|
294
294
|
export const FAVICON_ICO_B64 = `AAABAAMAEBAAAAEAIADIAAAANgAAACAgAAABACAACAEAAP4AAAAwMAAAAQAgAGcBAAAGAgAiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAeklEQVQ4jWNgoDa4/L93/uX/vf8J4577OAzouU+cAb3zMTSf/9+vQKTm/xf/9yRgGHDxf08CsqINV8vBGJsBIMsI+r+g3Q+MyfZ/AU4DiPR/AQ4DiPL/ZTwGEOX/yzgNICH+C7C7gPj434AlGon2/2UcmGj/0y/9UwoAAEX+8tkvEHwAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAAJcEhZcwAACxMAAAsTAQCanBgAAAC6SURBVFiF7ZbRDYMwDEQzwcEIDFC6QJXf0jEYKBEjMBJCGYBRXNEFepZshaqx5O+8+HQ+h9DqS22yDEWy2HY6Alu7pNkeIK80QJG8WgOcn1IApMMa4JSVenxr+svF9X88bxKnsZ7+6PpPV/M/1ADG/ocSwNz/UAKY+x8qAIf9D90E7Pc/FAAu+x8KAJf9DxrAKf/BT8An/0ECuOU/SAC3/I/TKPF1r6N/4bvdf4OL/oXqpn/6kfv/r+sNLlrC+A4T1ksAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAMAAAADAIBgAAAFcC+YcAAAAJcEhZcwAACxMAAAsTAQCanBgAAAEZSURBVGiB7ZjBDcJADARTAVBCKKKGSwfpgo+PlHDfQDOWSQGpBIwuD/7EVpYIr2Qpr+hGXln2Nk0otL0mzWXSrJii2QGAZhxALqbHsw4t8PEqSskEUH+ABGAdWhNA+F/D/+sV/teY/9vNf3mS0piWerxof/OfxqSH42mpfOv2N//7y/kDUL935//eFSBvv/94Aghi//EEYMT+4wdAmP3fsQMFsv97AQhq//cCYNT+7wNAuPvXqQMFdv96AAjy/vUAYOT9awcgAANi40iAAAn3/00EAB2U7f56m/2eQf30E14yR/0AAAABJRU5ErkJggg==`;
|
|
295
295
|
export const FAVICON_32_PNG_B64 = `iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAuklEQVRYhe2W0Q2DMAxEM8HBCAxQukCV39IxGCgRIzASQhmAUVzRBXqWbIWqseTvvPh0PofQ6kttsgxFsth2OgJbu6TZHiCvNECRvFoDnJ9SAKTDGuCUlXp8a/rLxfV/PG8Sp7Ge/uj6T1fzP9QAxv6HEsDc/1ACmPsfKgCH/Q/dBOz3PxQALvsfCgCX/Q8awCn/wU/AJ/9BArjlP0gAt/yP0yjxda+jf+G73X+Di/6F6qZ/+pH7/6/rDS5awvgOE9ZLAAAAAElFTkSuQmCC`;
|
|
296
296
|
export const APPLE_TOUCH_ICON_PNG_B64 = `iVBORw0KGgoAAAANSUhEUgAAALQAAAC0CAYAAAA9zQYyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGKUlEQVR4nO2bzWqdVRSGN72AtqO0WicWJ1KtoTi0dGjTK8gFGGtnH1ghJpXOw1l0kHoTUvlIU6rQa9Dg2R9W8OcK2guwky0nkIGU0kTfsvZZ63nhnWWwz7ufnTwcSCmEEEIIIYQQQgghhBBCCCGEEEII6SG12Xptsyd0Fm2DrZIxtdlYmzVq0TYYSra0dvfUvM2edTA+bdoNpnZvtWTL4kMDU7zHNG+z54tfViVbFn+WvMen9iY2GEvG4M9hH9RQsgV/jtsJf/a/BGqSDfBnYGrBNsCfO7gE2mQb4M8AZWE2wJ87uARqkg3wZ2CK9pjGkjF8/xy2Q8kWvn+O24nvn/0vgZpkA/wZmKI9prFkDP4ctkPJFvw5bif82f8SqEk2wJ+BKdpjGkvG4M9hO5RswZ/jdsKf/S+BmmQD/BmYoj2msWQM/hy2Q8kW/DluJ/zZ/xKoSTbAn4Ep2mMaS8bgz2E7lGzBn+N2wp/9L4GaZAP8GZiiPaaxZAz+HLZDyRb8OW4n/Nn/EqhJNsCfgSnaYxpLxuDPYTuUbMGf43bCn5evj3/farsPNw77+I9t9/PUToo/L1n3ft1sn3z6YTt95uy/evX65bb3dNP9fNW/+POy9Lufvmzn3l55Ceajnr+w0h4c3HY/Z/Ut/rwM/fnvnfb+6ruvhPmol65cbAcvdtzPW52KPy9Jd/c+ey3MR72/v+F+3upQ/HmJenN77dhAf3Fnzf281af487J0/da1YwO9+Fnv81af4s8dXAJAN81G+HMHoAK0SfbBnzuAFKBNuRH+7A0pQJtyI/zZG1KANtk++HMHkAK0SbbBnzsAFKBNuQ/+7A0oQJtyH/zZG1CANtk2+HMHgAK0SXbBnzuAE6BNuQ3+7A0nQJtyG/zZG04ANtku+HMHcAK0STbBnzsAE6BNuQv+7A0mQJtyF/zZG0yANtkm+HMHYAK0SfbAnzuAEqBNuQn+7A0lQJtyE/zZG0qANtke+HMHUAK0SbbAnzsAEgBNuQf+7A0kQJtyD/zZG0iANtkW+HMHQAK0SXbAnzuAEaBNuQX+7A0jQJtyC/zZG0aANtkO+HMHMAK0STbAnzsAEQBNuQP+7A0iQJtyB/zZG0SANtkG+HMHIAK0ZgP8uQMIAdqUG+DP3hACtCk3wJ+9IQRok22AP3cAIUCbZAP8uQMAAdqUG+DP3gACtCk3wJ+9AQRok22AP3cAIECbZAP8uQP4ANqUG+DP3vABtCk3wJ+94QNok22AP3cAH0CbZAP8uQPwANqUG+DP3uABtCk3wJ+9wQNok22AP3cAHkCbZAP8uQPoANqUG+DP3tABtCk3wJ+9oQNok22AP3cAHUCbZAP8uQPgANqUG+DP3sABtCk3wJ+9gQNok22AP3cAHECbZAP8uQPYANqUG+DP3rABtCk3wJ+9YQNok22AP3cAG0CbZAP8uQPQANqUG+DP3qABtCk3wJ+9QQNok22AP3cAGkCbZAP8uQPIANqUG+DPmXpze62dPnP2WL31zQ3389aTF3/O1N2HG8cG+ttHn7uft56w+HOyHrzYaZeuXHwtzB98/N7hz3qft56g+HPSPji43c5fWHklzG+9c659/8tX7uesJy/+nLV7Tzfb1euXX4L52o2P2v5vX7ufr/634s/Z+8Of2+3+/sZhf/zrjvt56v8o/tzBJVCTbIA/A1O0xzSWjFl88A7Gp02+Af4MWHEe1tTurZZsWXxo7+GpyTfAnwEr2sMaS8bgz2E7lGxp7e6peZs962B82rQb4M9AFeZRzdvs+eKXVcmWxZ8l7/GpvYnW/d2iwC0CBAgAIAAAAAAAAgAAAAAAQIECBAgAIAAAAAAAAgAAAAAAQIECBAgAIAAAAAAAAgAAAAAAQIECBAgAIAAAAAAAAgAAAAAAQIEC`;
|
|
297
|
-
/** Head component
|
|
297
|
+
/** Head component: charset, viewport, favicon, CSS link. */
|
|
298
298
|
export const SITE_META_HTML = `<meta charset="UTF-8" />
|
|
299
299
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
300
300
|
<meta name="description" content="A fast, modern website built with Bascik." />
|
|
@@ -544,7 +544,7 @@ export const MY_COUNTER_CSS = `.counter {
|
|
|
544
544
|
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); opacity: 1; }
|
|
545
545
|
}
|
|
546
546
|
`;
|
|
547
|
-
/** Interactive counter
|
|
547
|
+
/** Interactive counter: two instances on a page stay fully independent. */
|
|
548
548
|
export const MY_COUNTER_HTML = `<style>
|
|
549
549
|
${MY_COUNTER_CSS}</style>
|
|
550
550
|
<div class="counter">
|
|
@@ -665,7 +665,7 @@ ${body}
|
|
|
665
665
|
</body>
|
|
666
666
|
</html>
|
|
667
667
|
`;
|
|
668
|
-
export const indexPage = (brand) => pageShell(`Home
|
|
668
|
+
export const indexPage = (brand) => pageShell(`Home - ${brand}`, brand, ` <section class="hero">
|
|
669
669
|
<div class="container">
|
|
670
670
|
<p class="section-label">Welcome</p>
|
|
671
671
|
<h1>Build fast with <span>${brand}</span></h1>
|
|
@@ -709,14 +709,14 @@ export const indexPage = (brand) => pageShell(`Home — ${brand}`, brand, ` <
|
|
|
709
709
|
<div class="container">
|
|
710
710
|
<p class="section-label">Interactive</p>
|
|
711
711
|
<h2>Counter component</h2>
|
|
712
|
-
<p>Each instance holds its own state. Place the same component twice
|
|
712
|
+
<p>Each instance holds its own state. Place the same component twice, and they stay independent.</p>
|
|
713
713
|
<div style="display:flex;gap:48px;flex-wrap:wrap;margin-top:24px;">
|
|
714
714
|
<my-counter />
|
|
715
715
|
<my-counter />
|
|
716
716
|
</div>
|
|
717
717
|
</div>
|
|
718
718
|
</section>`);
|
|
719
|
-
export const aboutPage = (brand) => pageShell(`About
|
|
719
|
+
export const aboutPage = (brand) => pageShell(`About - ${brand}`, brand, ` <div class="container">
|
|
720
720
|
<section class="section">
|
|
721
721
|
<p class="section-label">About</p>
|
|
722
722
|
<h1>About us</h1>
|
|
@@ -738,7 +738,7 @@ export const aboutPage = (brand) => pageShell(`About — ${brand}`, brand, `
|
|
|
738
738
|
</div>
|
|
739
739
|
</section>
|
|
740
740
|
</div>`);
|
|
741
|
-
export const contactPage = (brand) => pageShell(`Contact
|
|
741
|
+
export const contactPage = (brand) => pageShell(`Contact - ${brand}`, brand, ` <div class="container">
|
|
742
742
|
<section class="section">
|
|
743
743
|
<p class="section-label">Contact</p>
|
|
744
744
|
<h1>Get in touch</h1>
|
|
@@ -761,7 +761,7 @@ export const contactPage = (brand) => pageShell(`Contact — ${brand}`, brand, `
|
|
|
761
761
|
</form>
|
|
762
762
|
</section>
|
|
763
763
|
</div>`);
|
|
764
|
-
export const notFoundPage = (brand) => pageShell(`404
|
|
764
|
+
export const notFoundPage = (brand) => pageShell(`404 - ${brand}`, brand, ` <div class="container">
|
|
765
765
|
<section class="section" style="text-align:center;">
|
|
766
766
|
<p class="section-label">Error</p>
|
|
767
767
|
<h1 style="font-size:clamp(4rem,12vw,8rem);color:var(--accent);margin-bottom:8px;">404</h1>
|
package/dist/scaffold.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export interface CliOptions {
|
|
2
2
|
yesFlag: boolean;
|
|
3
3
|
noDevFlag: boolean;
|
|
4
|
+
noInstallFlag: boolean;
|
|
4
5
|
}
|
|
5
6
|
|
|
6
7
|
export function parseCliOptions(args: string[]): CliOptions {
|
|
7
8
|
return {
|
|
8
9
|
yesFlag: args.includes("-y") || args.includes("--yes"),
|
|
9
10
|
noDevFlag: args.includes("--no-dev"),
|
|
11
|
+
noInstallFlag: args.includes("--no-install"),
|
|
10
12
|
};
|
|
11
|
-
}
|
|
13
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { parseCliOptions } from "./cli.js";
|
|
|
6
6
|
import { scaffold, validateProjectName } from "./scaffold.js";
|
|
7
7
|
|
|
8
8
|
const args = process.argv.slice(2);
|
|
9
|
-
const { yesFlag, noDevFlag } = parseCliOptions(args);
|
|
9
|
+
const { yesFlag, noDevFlag, noInstallFlag } = parseCliOptions(args);
|
|
10
10
|
const nameArg = args.find((a) => !a.startsWith("-"));
|
|
11
11
|
|
|
12
12
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -35,7 +35,7 @@ let shouldInstall: boolean;
|
|
|
35
35
|
let shouldDev: boolean;
|
|
36
36
|
|
|
37
37
|
if (yesFlag) {
|
|
38
|
-
shouldInstall =
|
|
38
|
+
shouldInstall = !noInstallFlag;
|
|
39
39
|
shouldDev = !noDevFlag;
|
|
40
40
|
} else {
|
|
41
41
|
const installAnswer = await rl.question("Install dependencies now? (Y/n) ");
|
package/src/scaffold.test.ts
CHANGED
|
@@ -60,6 +60,7 @@ describe("parseCliOptions", () => {
|
|
|
60
60
|
expect(parseCliOptions(["my-site", "-y"])).toEqual({
|
|
61
61
|
yesFlag: true,
|
|
62
62
|
noDevFlag: false,
|
|
63
|
+
noInstallFlag: false,
|
|
63
64
|
});
|
|
64
65
|
});
|
|
65
66
|
|
|
@@ -67,6 +68,17 @@ describe("parseCliOptions", () => {
|
|
|
67
68
|
expect(parseCliOptions(["my-site", "--yes", "--no-dev"])).toEqual({
|
|
68
69
|
yesFlag: true,
|
|
69
70
|
noDevFlag: true,
|
|
71
|
+
noInstallFlag: false,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("supports skipping install with --no-install", () => {
|
|
76
|
+
expect(
|
|
77
|
+
parseCliOptions(["my-site", "-y", "--no-install", "--no-dev"]),
|
|
78
|
+
).toEqual({
|
|
79
|
+
yesFlag: true,
|
|
80
|
+
noDevFlag: true,
|
|
81
|
+
noInstallFlag: true,
|
|
70
82
|
});
|
|
71
83
|
});
|
|
72
84
|
});
|
|
@@ -120,9 +132,9 @@ describe("PACKAGE_JSON", () => {
|
|
|
120
132
|
expect(pkg.devDependencies["@playwright/test"]).toBeDefined();
|
|
121
133
|
});
|
|
122
134
|
|
|
123
|
-
it("
|
|
135
|
+
it("uses the current Bascik prerelease dependency", () => {
|
|
124
136
|
const pkg = JSON.parse(PACKAGE_JSON("my-app"));
|
|
125
|
-
expect(pkg.dependencies["@bascik/bascik"]).
|
|
137
|
+
expect(pkg.dependencies["@bascik/bascik"]).toBe("^1.0.0-rc.3");
|
|
126
138
|
});
|
|
127
139
|
|
|
128
140
|
it("uses the supplied name", () => {
|
package/src/scaffold.ts
CHANGED
|
@@ -32,7 +32,7 @@ export const PACKAGE_JSON = (name: string): string =>
|
|
|
32
32
|
e2e: "playwright test --config e2e/playwright.config.ts",
|
|
33
33
|
},
|
|
34
34
|
dependencies: {
|
|
35
|
-
"@bascik/bascik": "^1.0.0-rc.
|
|
35
|
+
"@bascik/bascik": "^1.0.0-rc.3",
|
|
36
36
|
},
|
|
37
37
|
devDependencies: {
|
|
38
38
|
"@bascik/language-server": "^0.1.0-rc.1",
|
|
@@ -325,7 +325,7 @@ export const FAVICON_32_PNG_B64 = `iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0A
|
|
|
325
325
|
|
|
326
326
|
export const APPLE_TOUCH_ICON_PNG_B64 = `iVBORw0KGgoAAAANSUhEUgAAALQAAAC0CAYAAAA9zQYyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGKUlEQVR4nO2bzWqdVRSGN72AtqO0WicWJ1KtoTi0dGjTK8gFGGtnH1ghJpXOw1l0kHoTUvlIU6rQa9Dg2R9W8OcK2guwky0nkIGU0kTfsvZZ63nhnWWwz7ufnTwcSCmEEEIIIYQQQgghhBBCCCGEEEII6SG12Xptsyd0Fm2DrZIxtdlYmzVq0TYYSra0dvfUvM2edTA+bdoNpnZvtWTL4kMDU7zHNG+z54tfViVbFn+WvMen9iY2GEvG4M9hH9RQsgV/jtsJf/a/BGqSDfBnYGrBNsCfO7gE2mQb4M8AZWE2wJ87uARqkg3wZ2CK9pjGkjF8/xy2Q8kWvn+O24nvn/0vgZpkA/wZmKI9prFkDP4ctkPJFvw5bif82f8SqEk2wJ+BKdpjGkvG4M9hO5RswZ/jdsKf/S+BmmQD/BmYoj2msWQM/hy2Q8kW/DluJ/zZ/xKoSTbAn4Ep2mMaS8bgz2E7lGzBn+N2wp/9L4GaZAP8GZiiPaaxZAz+HLZDyRb8OW4n/Nn/EqhJNsCfgSnaYxpLxuDPYTuUbMGf43bCn5evj3/farsPNw77+I9t9/PUToo/L1n3ft1sn3z6YTt95uy/evX65bb3dNP9fNW/+POy9Lufvmzn3l55Ceajnr+w0h4c3HY/Z/Ut/rwM/fnvnfb+6ruvhPmol65cbAcvdtzPW52KPy9Jd/c+ey3MR72/v+F+3upQ/HmJenN77dhAf3Fnzf281af487J0/da1YwO9+Fnv81af4s8dXAJAN81G+HMHoAK0SfbBnzuAFKBNuRH+7A0pQJtyI/zZG1KANtk++HMHkAK0SbbBnzsAFKBNuQ/+7A0oQJtyH/zZG1CANtk2+HMHgAK0SXbBnzuAE6BNuQ3+7A0nQJtyG/zZG04ANtku+HMHcAK0STbBnzsAE6BNuQv+7A0mQJtyF/zZG0yANtkm+HMHYAK0SfbAnzuAEqBNuQn+7A0lQJtyE/zZG0qANtke+HMHUAK0SbbAnzsAEgBNuQf+7A0kQJtyD/zZG0iANtkW+HMHQAK0SXbAnzuAEaBNuQX+7A0jQJtyC/zZG0aANtkO+HMHMAK0STbAnzsAEQBNuQP+7A0iQJtyB/zZG0SANtkG+HMHIAK0ZgP8uQMIAdqUG+DP3hACtCk3wJ+9IQRok22AP3cAIUCbZAP8uQMAAdqUG+DP3gACtCk3wJ+9AQRok22AP3cAIECbZAP8uQP4ANqUG+DP3vABtCk3wJ+94QNok22AP3cAH0CbZAP8uQPwANqUG+DP3uABtCk3wJ+9wQNok22AP3cAHkCbZAP8uQPoANqUG+DP3tABtCk3wJ+9oQNok22AP3cAHUCbZAP8uQPgANqUG+DP3sABtCk3wJ+9gQNok22AP3cAHECbZAP8uQPYANqUG+DP3rABtCk3wJ+9YQNok22AP3cAG0CbZAP8uQPQANqUG+DP3qABtCk3wJ+9QQNok22AP3cAGkCbZAP8uQPIANqUG+DPmXpze62dPnP2WL31zQ3389aTF3/O1N2HG8cG+ttHn7uft56w+HOyHrzYaZeuXHwtzB98/N7hz3qft56g+HPSPji43c5fWHklzG+9c659/8tX7uesJy/+nLV7Tzfb1euXX4L52o2P2v5vX7ufr/634s/Z+8Of2+3+/sZhf/zrjvt56v8o/tzBJVCTbIA/A1O0xzSWjFl88A7Gp02+Af4MWHEe1tTurZZsWXxo7+GpyTfAnwEr2sMaS8bgz2E7lGxp7e6peZs962B82rQb4M9AFeZRzdvs+eKXVcmWxZ8l7/GpvYnW/d2iwC0CBAgAIAAAAAAAAgAAAAAAQIECBAgAIAAAAAAAAgAAAAAAQIECBAgAIAAAAAAAAgAAAAAAQIECBAgAIAAAAAAAAgAAAAAAQIEC`;
|
|
327
327
|
|
|
328
|
-
/** Head component
|
|
328
|
+
/** Head component: charset, viewport, favicon, CSS link. */
|
|
329
329
|
export const SITE_META_HTML = `<meta charset="UTF-8" />
|
|
330
330
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
331
331
|
<meta name="description" content="A fast, modern website built with Bascik." />
|
|
@@ -583,7 +583,7 @@ export const MY_COUNTER_CSS = `.counter {
|
|
|
583
583
|
}
|
|
584
584
|
`;
|
|
585
585
|
|
|
586
|
-
/** Interactive counter
|
|
586
|
+
/** Interactive counter: two instances on a page stay fully independent. */
|
|
587
587
|
export const MY_COUNTER_HTML = `<style>
|
|
588
588
|
${MY_COUNTER_CSS}</style>
|
|
589
589
|
<div class="counter">
|
|
@@ -718,7 +718,7 @@ ${body}
|
|
|
718
718
|
`;
|
|
719
719
|
|
|
720
720
|
export const indexPage = (brand: string): string =>
|
|
721
|
-
pageShell(`Home
|
|
721
|
+
pageShell(`Home - ${brand}`, brand, ` <section class="hero">
|
|
722
722
|
<div class="container">
|
|
723
723
|
<p class="section-label">Welcome</p>
|
|
724
724
|
<h1>Build fast with <span>${brand}</span></h1>
|
|
@@ -762,7 +762,7 @@ export const indexPage = (brand: string): string =>
|
|
|
762
762
|
<div class="container">
|
|
763
763
|
<p class="section-label">Interactive</p>
|
|
764
764
|
<h2>Counter component</h2>
|
|
765
|
-
<p>Each instance holds its own state. Place the same component twice
|
|
765
|
+
<p>Each instance holds its own state. Place the same component twice, and they stay independent.</p>
|
|
766
766
|
<div style="display:flex;gap:48px;flex-wrap:wrap;margin-top:24px;">
|
|
767
767
|
<my-counter />
|
|
768
768
|
<my-counter />
|
|
@@ -771,7 +771,7 @@ export const indexPage = (brand: string): string =>
|
|
|
771
771
|
</section>`);
|
|
772
772
|
|
|
773
773
|
export const aboutPage = (brand: string): string =>
|
|
774
|
-
pageShell(`About
|
|
774
|
+
pageShell(`About - ${brand}`, brand, ` <div class="container">
|
|
775
775
|
<section class="section">
|
|
776
776
|
<p class="section-label">About</p>
|
|
777
777
|
<h1>About us</h1>
|
|
@@ -795,7 +795,7 @@ export const aboutPage = (brand: string): string =>
|
|
|
795
795
|
</div>`);
|
|
796
796
|
|
|
797
797
|
export const contactPage = (brand: string): string =>
|
|
798
|
-
pageShell(`Contact
|
|
798
|
+
pageShell(`Contact - ${brand}`, brand, ` <div class="container">
|
|
799
799
|
<section class="section">
|
|
800
800
|
<p class="section-label">Contact</p>
|
|
801
801
|
<h1>Get in touch</h1>
|
|
@@ -820,7 +820,7 @@ export const contactPage = (brand: string): string =>
|
|
|
820
820
|
</div>`);
|
|
821
821
|
|
|
822
822
|
export const notFoundPage = (brand: string): string =>
|
|
823
|
-
pageShell(`404
|
|
823
|
+
pageShell(`404 - ${brand}`, brand, ` <div class="container">
|
|
824
824
|
<section class="section" style="text-align:center;">
|
|
825
825
|
<p class="section-label">Error</p>
|
|
826
826
|
<h1 style="font-size:clamp(4rem,12vw,8rem);color:var(--accent);margin-bottom:8px;">404</h1>
|