@reqquest/ui 1.17.0 → 1.18.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/app/env.template +5 -0
- package/app/runtime/apply-env.sh +10 -0
- package/app/runtime/nginx.conf +37 -0
- package/app/src/app.css +21 -0
- package/app/src/app.d.ts +13 -0
- package/app/src/app.html +12 -0
- package/app/src/internal/api.ts +1707 -0
- package/app/src/internal/appreq-utils.ts +33 -0
- package/app/src/internal/components/AnnouncementBanner.svelte +47 -0
- package/app/src/internal/components/AppRequestCard.svelte +173 -0
- package/app/src/internal/components/ApplicantOptOutModal.svelte +78 -0
- package/app/src/internal/components/ApplicantProgramList.svelte +276 -0
- package/app/src/internal/components/ApplicantProgramListTooltip.svelte +44 -0
- package/app/src/internal/components/ApplicantPromptPage.svelte +136 -0
- package/app/src/internal/components/ApplicantPromptSkeleton.svelte +12 -0
- package/app/src/internal/components/ApplicationDetailsView.svelte +369 -0
- package/app/src/internal/components/ButtonLoadingIcon.svelte +28 -0
- package/{dist → app/src/internal}/components/DelayedSkeleton.svelte +2 -2
- package/app/src/internal/components/FieldNestedMultiselect.svelte +270 -0
- package/app/src/internal/components/IntroPanel.svelte +41 -0
- package/app/src/internal/components/MissingDefinitionNotification.svelte +20 -0
- package/app/src/internal/components/PeriodPanel.svelte +125 -0
- package/app/src/internal/components/ProgramStatusCell.svelte +134 -0
- package/app/src/internal/components/RenderDisplayComponent.svelte +42 -0
- package/app/src/internal/components/ReviewerActions.svelte +171 -0
- package/app/src/internal/components/ReviewerQuestions.svelte +444 -0
- package/app/src/internal/components/StatusMessageList.svelte +54 -0
- package/app/src/internal/components/SystemDeterminationNotice.svelte +37 -0
- package/app/src/internal/components/TabLinks.svelte +265 -0
- package/app/src/internal/components/WarningIconYellow.svelte +22 -0
- package/app/src/internal/components/index.ts +19 -0
- package/app/src/internal/csv.ts +30 -0
- package/app/src/internal/index.ts +8 -0
- package/app/src/internal/prompt-save-queue.ts +91 -0
- package/app/src/internal/prompt-utils.ts +40 -0
- package/app/src/internal/status-utils.ts +503 -0
- package/app/src/internal/stores/IStateStore.ts +5 -0
- package/app/src/internal/util.ts +27 -0
- package/app/src/routes/+error.svelte +4 -0
- package/app/src/routes/+layout.svelte +134 -0
- package/app/src/routes/+layout.ts +18 -0
- package/app/src/routes/+page.ts +14 -0
- package/app/src/routes/announcement/+page.svelte +164 -0
- package/app/src/routes/announcement/+page.ts +16 -0
- package/app/src/routes/dashboards/applicant/+page.svelte +494 -0
- package/app/src/routes/dashboards/applicant/+page.ts +95 -0
- package/app/src/routes/dashboards/reviewer/+page.svelte +143 -0
- package/app/src/routes/dashboards/reviewer/+page.ts +43 -0
- package/app/src/routes/periods/+page.svelte +158 -0
- package/app/src/routes/periods/+page.ts +13 -0
- package/app/src/routes/periods/[id]/configure/+page.svelte +150 -0
- package/app/src/routes/periods/[id]/configure/+page.ts +10 -0
- package/app/src/routes/requests/+page.svelte +246 -0
- package/app/src/routes/requests/+page.ts +24 -0
- package/app/src/routes/requests/[id]/+layout.ts +11 -0
- package/app/src/routes/requests/[id]/accept/+layout.svelte +80 -0
- package/app/src/routes/requests/[id]/accept/+layout.ts +12 -0
- package/app/src/routes/requests/[id]/accept/+page.ts +13 -0
- package/app/src/routes/requests/[id]/accept/[promptId]/+page.svelte +7 -0
- package/app/src/routes/requests/[id]/accept/[promptId]/+page.ts +10 -0
- package/app/src/routes/requests/[id]/accept/review/+page.svelte +87 -0
- package/app/src/routes/requests/[id]/apply/+layout.svelte +181 -0
- package/app/src/routes/requests/[id]/apply/+layout.ts +12 -0
- package/app/src/routes/requests/[id]/apply/+page.ts +14 -0
- package/app/src/routes/requests/[id]/apply/ProgressNavContainer.svelte +42 -0
- package/app/src/routes/requests/[id]/apply/[promptId]/+page.svelte +23 -0
- package/app/src/routes/requests/[id]/apply/[promptId]/+page.ts +11 -0
- package/app/src/routes/requests/[id]/apply/programs/+page.svelte +71 -0
- package/app/src/routes/requests/[id]/apply/review/+page.svelte +102 -0
- package/app/src/routes/requests/[id]/approve/+layout.svelte +114 -0
- package/app/src/routes/requests/[id]/approve/+page.ts +14 -0
- package/app/src/routes/requests/[id]/approve/ApproveLayout.svelte +164 -0
- package/app/src/routes/requests/[id]/approve/[programKey]/+page.svelte +396 -0
- package/app/src/routes/requests/[id]/approve/[programKey]/+page.ts +15 -0
- package/app/src/routes/requests/[id]/approve/activity/+page.svelte +66 -0
- package/app/src/routes/requests/[id]/approve/activity/+page.ts +12 -0
- package/app/src/routes/requests/[id]/approve/export/+page.ts +12 -0
- package/app/src/routes/requests/[id]/approve/export/+page@[id].svelte +41 -0
- package/app/src/routes/requests/[id]/export/+page.svelte +32 -0
- package/app/src/routes/requests/[id]/export/+page.ts +12 -0
- package/app/src/routes/roles/+layout.svelte +16 -0
- package/app/src/routes/roles/+layout.ts +14 -0
- package/app/src/routes/roles/+page.svelte +225 -0
- package/app/src/routes/roles/+page.ts +13 -0
- package/app/src/routes/roles/[id]/+layout.ts +10 -0
- package/app/src/routes/roles/[id]/+page.svelte +335 -0
- package/app/src/routes/roles/[id]/+page.ts +10 -0
- package/app/src/routes/roles/[id]/ControlWithTooltip.svelte +15 -0
- package/app/src/routes/roles/[id]/TagsWithTooltip.svelte +42 -0
- package/app/src/routes/roles/users/+layout.ts +13 -0
- package/app/src/routes/roles/users/+page.svelte +46 -0
- package/app/src/routes/roles/users/+page.ts +90 -0
- package/app/static/favicon.png +0 -0
- package/bin/reqquest-ui.js +117 -0
- package/cli/config.js +105 -0
- package/cli/sync.js +296 -0
- package/cli/util.js +29 -0
- package/dist/components.md +0 -4
- package/package.json +29 -15
- package/dist/components/DelayedSkeleton.svelte.d.ts +0 -21
package/cli/config.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SvelteKit and Vite configuration for a downstream ReqQuest UI.
|
|
3
|
+
*
|
|
4
|
+
* `reqquest-ui sync` writes .reqquest/svelte.config.js and .reqquest/vite.config.js as two-line stubs
|
|
5
|
+
* that import these functions by absolute path. Keeping the real configuration here, inside the
|
|
6
|
+
* package, means every plugin below resolves from @reqquest/ui's own dependencies - the downstream
|
|
7
|
+
* project never declares vite, the adapter, tailwind or the preprocessors, so their versions are
|
|
8
|
+
* whatever this release of @reqquest/ui was built and tested with.
|
|
9
|
+
*
|
|
10
|
+
* Mirrors ui/svelte.config.js and ui/vite.config.ts; change them together.
|
|
11
|
+
*/
|
|
12
|
+
import { join } from 'node:path'
|
|
13
|
+
import adapter from '@sveltejs/adapter-static'
|
|
14
|
+
import { sveltekit } from '@sveltejs/kit/vite'
|
|
15
|
+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
|
|
16
|
+
import carbonSvelteTailwind from '@txstate-mws/carbon-svelte/tailwind'
|
|
17
|
+
import autoprefixer from 'autoprefixer'
|
|
18
|
+
import { optimizeImports } from 'carbon-preprocess-svelte'
|
|
19
|
+
import tailwindcss from 'tailwindcss'
|
|
20
|
+
import { packageDir } from './util.js'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {{ projectRoot: string, appRoot: string, basePath?: string }} opts
|
|
24
|
+
* projectRoot - the downstream project (holds src/local, src/routes, package.json)
|
|
25
|
+
* appRoot - the generated .reqquest/ directory SvelteKit runs in
|
|
26
|
+
* @returns {import('@sveltejs/kit').Config}
|
|
27
|
+
*/
|
|
28
|
+
export function svelteConfig ({ projectRoot, appRoot, basePath = '' }) {
|
|
29
|
+
return {
|
|
30
|
+
preprocess: [vitePreprocess(), optimizeImports()],
|
|
31
|
+
kit: {
|
|
32
|
+
adapter: adapter({
|
|
33
|
+
pages: join(projectRoot, 'build'),
|
|
34
|
+
assets: join(projectRoot, 'build'),
|
|
35
|
+
fallback: 'index.html',
|
|
36
|
+
precompress: true
|
|
37
|
+
}),
|
|
38
|
+
output: {
|
|
39
|
+
preloadStrategy: 'preload-mjs'
|
|
40
|
+
},
|
|
41
|
+
paths: {
|
|
42
|
+
base: basePath
|
|
43
|
+
},
|
|
44
|
+
files: {
|
|
45
|
+
// $lib keeps meaning the project's own src/lib, as it would in any SvelteKit app
|
|
46
|
+
lib: join(projectRoot, 'src/lib')
|
|
47
|
+
},
|
|
48
|
+
alias: {
|
|
49
|
+
$internal: 'src/internal',
|
|
50
|
+
// the downstream registry is not copied: it is aliased in place so the editor, HMR and
|
|
51
|
+
// svelte-check all work on the files the developer actually edits
|
|
52
|
+
$local: join(projectRoot, 'src/local')
|
|
53
|
+
},
|
|
54
|
+
typescript: {
|
|
55
|
+
// SvelteKit's generated tsconfig only includes the app root, which src/local and src/lib sit outside of
|
|
56
|
+
config (tsconfig) {
|
|
57
|
+
for (const dir of ['src/local', 'src/lib']) {
|
|
58
|
+
const abs = join(projectRoot, dir)
|
|
59
|
+
tsconfig.include.push(`${abs}/**/*.ts`, `${abs}/**/*.js`, `${abs}/**/*.svelte`)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {{ projectRoot: string, appRoot: string }} opts
|
|
69
|
+
* @returns {import('vite').UserConfig}
|
|
70
|
+
*/
|
|
71
|
+
export function viteConfig ({ projectRoot, appRoot }) {
|
|
72
|
+
const globs = '**/*.{html,js,svelte,ts}'
|
|
73
|
+
return {
|
|
74
|
+
plugins: [sveltekit()],
|
|
75
|
+
build: {
|
|
76
|
+
sourcemap: true
|
|
77
|
+
},
|
|
78
|
+
optimizeDeps: {
|
|
79
|
+
exclude: ['carbon-icons-svelte']
|
|
80
|
+
},
|
|
81
|
+
server: {
|
|
82
|
+
fs: {
|
|
83
|
+
allow: [projectRoot, packageDir('@txstate-mws/carbon-svelte', appRoot)]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
// inline so that no postcss.config.js / tailwind.config.js is needed in either the project or
|
|
87
|
+
// .reqquest/, and so the plugins resolve from this package rather than the project
|
|
88
|
+
css: {
|
|
89
|
+
postcss: {
|
|
90
|
+
plugins: [
|
|
91
|
+
tailwindcss({
|
|
92
|
+
content: [
|
|
93
|
+
join(appRoot, 'src', globs),
|
|
94
|
+
join(projectRoot, 'src/local', globs),
|
|
95
|
+
join(projectRoot, 'src/lib', globs),
|
|
96
|
+
join(packageDir('@txstate-mws/carbon-svelte', appRoot), globs)
|
|
97
|
+
],
|
|
98
|
+
plugins: [carbonSvelteTailwind]
|
|
99
|
+
}),
|
|
100
|
+
autoprefixer()
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
package/cli/sync.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assembles .reqquest/ - a complete SvelteKit project - from the app shell shipped in this package
|
|
3
|
+
* plus the downstream project's own files.
|
|
4
|
+
*
|
|
5
|
+
* node_modules/@reqquest/ui/app/src/routes base routes (read-only)
|
|
6
|
+
* + <project>/src/routes developer overrides and additions
|
|
7
|
+
* = .reqquest/src/routes what SvelteKit builds
|
|
8
|
+
*
|
|
9
|
+
* Overlay rules, applied in this order:
|
|
10
|
+
* 1. package.json "reqquest": { "disableRoutes": ["roles/users"] } removes those base route folders
|
|
11
|
+
* 2. a `.reqquest-replace` file in a developer folder removes the base folder of the same path, so
|
|
12
|
+
* the developer's version stands alone (use when an override page needs different load data)
|
|
13
|
+
* 3. every developer file is copied over the base; same path = override, new path = addition
|
|
14
|
+
*
|
|
15
|
+
* src/local is never copied - svelteConfig() aliases $local to it in place. src/internal is base-only:
|
|
16
|
+
* every route depends on it, so letting it be overridden would freeze it as public API.
|
|
17
|
+
*
|
|
18
|
+
* Overriding a base file forks it. reqquest-overrides.lock.json (committed, in the project root)
|
|
19
|
+
* records the hash of each base file at the time it was overridden, so an upgrade that changes the
|
|
20
|
+
* file underneath an override is reported instead of silently diverging.
|
|
21
|
+
*
|
|
22
|
+
* The generated tree is reconciled rather than wiped: unchanged files are not rewritten, so a
|
|
23
|
+
* running dev server only sees what actually changed, and .reqquest/.svelte-kit and the Vite cache
|
|
24
|
+
* survive.
|
|
25
|
+
*/
|
|
26
|
+
import { createHash } from 'node:crypto'
|
|
27
|
+
import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'
|
|
28
|
+
import { dirname, join, relative, resolve, sep } from 'node:path'
|
|
29
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
30
|
+
import { packageDir, readJson } from './util.js'
|
|
31
|
+
|
|
32
|
+
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
33
|
+
const APP = join(PACKAGE_ROOT, 'app')
|
|
34
|
+
const MARKER = '.reqquest-replace'
|
|
35
|
+
const LOCKFILE = 'reqquest-overrides.lock.json'
|
|
36
|
+
const GENERATED_NOTE = 'generated by `reqquest-ui sync` - do not edit; it is rewritten on every sync'
|
|
37
|
+
|
|
38
|
+
export class SyncError extends Error {}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {string} projectRoot
|
|
42
|
+
* @param {{ strict?: boolean, accept?: boolean, quiet?: boolean }} [opts]
|
|
43
|
+
* strict - fail instead of warn on drift or an out-of-date lockfile (CI / docker builds)
|
|
44
|
+
* accept - re-record the current base hashes in the lockfile, acknowledging any drift
|
|
45
|
+
* @returns {{ appRoot: string, warnings: string[] }}
|
|
46
|
+
*/
|
|
47
|
+
export function sync (projectRoot, { strict = false, accept = false, quiet = false } = {}) {
|
|
48
|
+
if (!existsSync(APP)) throw new SyncError(`${APP} is missing - this @reqquest/ui was not packed with its app shell.`)
|
|
49
|
+
const appRoot = join(projectRoot, '.reqquest')
|
|
50
|
+
const pkg = readJson(join(projectRoot, 'package.json'))
|
|
51
|
+
const options = pkg.reqquest ?? {}
|
|
52
|
+
const warnings = []
|
|
53
|
+
|
|
54
|
+
checkToolchain(projectRoot)
|
|
55
|
+
if (!existsSync(join(projectRoot, 'src/local/index.ts')) && !existsSync(join(projectRoot, 'src/local/index.js'))) {
|
|
56
|
+
throw new SyncError('src/local/index.ts not found. It must export `uiRegistry` - see docs/downstream-ui.md in the reqquest repo.')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** @type {Map<string, Buffer>} path relative to appRoot -> contents */
|
|
60
|
+
const files = new Map()
|
|
61
|
+
|
|
62
|
+
// -- src: base shell, then the route overlay
|
|
63
|
+
for (const rel of walk(join(APP, 'src'))) files.set(join('src', rel), readFileSync(join(APP, 'src', rel)))
|
|
64
|
+
const overrides = overlayRoutes(projectRoot, files, options, warnings)
|
|
65
|
+
|
|
66
|
+
// -- static: base, then the project's own
|
|
67
|
+
for (const rel of walk(join(APP, 'static'))) files.set(join('static', rel), readFileSync(join(APP, 'static', rel)))
|
|
68
|
+
for (const rel of walk(join(projectRoot, 'static'))) files.set(join('static', rel), readFileSync(join(projectRoot, 'static', rel)))
|
|
69
|
+
|
|
70
|
+
// -- config stubs and env
|
|
71
|
+
const configModule = pathToFileURL(join(PACKAGE_ROOT, 'cli/config.js')).href
|
|
72
|
+
const configArgs = JSON.stringify({ projectRoot, appRoot, basePath: options.basePath ?? '' })
|
|
73
|
+
files.set('svelte.config.js', Buffer.from(`// ${GENERATED_NOTE}\nimport { svelteConfig } from '${configModule}'\nexport default svelteConfig(${configArgs})\n`))
|
|
74
|
+
files.set('vite.config.js', Buffer.from(`// ${GENERATED_NOTE}\nimport { viteConfig } from '${configModule}'\nexport default viteConfig(${configArgs})\n`))
|
|
75
|
+
files.set('tsconfig.json', Buffer.from(JSON.stringify({
|
|
76
|
+
'//': GENERATED_NOTE,
|
|
77
|
+
extends: './.svelte-kit/tsconfig.json',
|
|
78
|
+
compilerOptions: { sourceMap: true, strictNullChecks: true, skipLibCheck: true }
|
|
79
|
+
}, null, 2) + '\n'))
|
|
80
|
+
// vite-plugin-svelte crawls the root package.json's dependencies to find svelte libraries to
|
|
81
|
+
// prebundle in dev, so list what @reqquest/ui's own package.json would - they resolve upward from here
|
|
82
|
+
const ui = readJson(join(PACKAGE_ROOT, 'package.json'))
|
|
83
|
+
files.set('package.json', Buffer.from(JSON.stringify({
|
|
84
|
+
'//': GENERATED_NOTE,
|
|
85
|
+
name: `${pkg.name ?? 'app'}-reqquest`,
|
|
86
|
+
private: true,
|
|
87
|
+
type: 'module',
|
|
88
|
+
dependencies: { '@reqquest/ui': ui.version, ...ui.dependencies, ...pkg.dependencies },
|
|
89
|
+
devDependencies: ui.peerDependencies
|
|
90
|
+
}, null, 2) + '\n'))
|
|
91
|
+
files.set('.env', mergeEnv(readFileSync(join(APP, 'env.template'), 'utf8'), join(projectRoot, '.env')))
|
|
92
|
+
|
|
93
|
+
reconcile(appRoot, files, ['src', 'static'])
|
|
94
|
+
updateLock(projectRoot, overrides, { strict, accept, warnings })
|
|
95
|
+
ensureRootTsconfig(projectRoot, warnings)
|
|
96
|
+
|
|
97
|
+
if (!quiet) for (const w of warnings) console.warn(`reqquest-ui: ${w}`)
|
|
98
|
+
return { appRoot, warnings }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The toolchain packages that must be single, top-level copies (svelte, kit, vite, the svelte vite
|
|
103
|
+
* plugin) are exact-pinned peers of @reqquest/ui. npm installs them for the project, but if the
|
|
104
|
+
* project's own package.json declares a different version npm only warns ("ERESOLVE overriding peer
|
|
105
|
+
* dependency") and installs that one. This is the check that actually stops the drift, and every
|
|
106
|
+
* reqquest-ui command runs it.
|
|
107
|
+
*/
|
|
108
|
+
function checkToolchain (projectRoot) {
|
|
109
|
+
const { peerDependencies = {}, version } = readJson(join(PACKAGE_ROOT, 'package.json'))
|
|
110
|
+
for (const [name, wanted] of Object.entries(peerDependencies)) {
|
|
111
|
+
let installed
|
|
112
|
+
try {
|
|
113
|
+
installed = readJson(join(packageDir(name, join(projectRoot, '.reqquest')), 'package.json')).version
|
|
114
|
+
} catch {
|
|
115
|
+
throw new SyncError(`${name} is not installed. It is a peer dependency of @reqquest/ui - run npm install.`)
|
|
116
|
+
}
|
|
117
|
+
if (installed !== wanted) {
|
|
118
|
+
throw new SyncError(`@reqquest/ui ${version} requires ${name} ${wanted} but ${installed} is installed. ` +
|
|
119
|
+
`Remove ${name} from your package.json - @reqquest/ui provides it - and reinstall.`)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Applies the developer's src/routes onto the base routes already in `files`.
|
|
126
|
+
* @returns {Map<string, string>} base route path (relative to routes/) -> hash of the base content
|
|
127
|
+
* the developer has forked, either by overriding the file or by replacing its folder
|
|
128
|
+
*/
|
|
129
|
+
function overlayRoutes (projectRoot, files, options, warnings) {
|
|
130
|
+
const routesKey = join('src', 'routes')
|
|
131
|
+
const baseRoutes = new Map()
|
|
132
|
+
for (const [path, content] of files) {
|
|
133
|
+
if (path.startsWith(routesKey + sep)) baseRoutes.set(relative(routesKey, path), content)
|
|
134
|
+
}
|
|
135
|
+
const deleteBase = (prefix) => {
|
|
136
|
+
let found = false
|
|
137
|
+
for (const rel of baseRoutes.keys()) {
|
|
138
|
+
if (rel === prefix || rel.startsWith(prefix + sep)) {
|
|
139
|
+
files.delete(join(routesKey, rel))
|
|
140
|
+
found = true
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return found
|
|
144
|
+
}
|
|
145
|
+
const forked = new Map()
|
|
146
|
+
|
|
147
|
+
for (const route of options.disableRoutes ?? []) {
|
|
148
|
+
const prefix = normalizeRoute(route)
|
|
149
|
+
if (!deleteBase(prefix)) warnings.push(`disableRoutes: "${route}" matches no ReqQuest route - check the spelling.`)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const devRoot = join(projectRoot, 'src', 'routes')
|
|
153
|
+
const devFiles = walk(devRoot)
|
|
154
|
+
|
|
155
|
+
for (const rel of devFiles) {
|
|
156
|
+
if (rel.split(sep).pop() !== MARKER) continue
|
|
157
|
+
const prefix = dirname(rel) === '.' ? '' : dirname(rel)
|
|
158
|
+
for (const [baseRel, content] of baseRoutes) {
|
|
159
|
+
if (prefix === '' || baseRel.startsWith(prefix + sep)) forked.set(baseRel, hash(content))
|
|
160
|
+
}
|
|
161
|
+
if (prefix === '') {
|
|
162
|
+
for (const baseRel of baseRoutes.keys()) files.delete(join(routesKey, baseRel))
|
|
163
|
+
} else if (!deleteBase(prefix)) {
|
|
164
|
+
warnings.push(`${join('src/routes', rel)} replaces "${prefix}", which is not a ReqQuest route - the marker does nothing.`)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const escapes = []
|
|
169
|
+
for (const rel of devFiles) {
|
|
170
|
+
if (rel.split(sep).pop() === MARKER) continue
|
|
171
|
+
const content = readFileSync(join(devRoot, rel))
|
|
172
|
+
escapes.push(...escapingImports(devRoot, rel, content))
|
|
173
|
+
if (baseRoutes.has(rel)) forked.set(rel, hash(baseRoutes.get(rel)))
|
|
174
|
+
files.set(join(routesKey, rel), content)
|
|
175
|
+
}
|
|
176
|
+
if (escapes.length) {
|
|
177
|
+
throw new SyncError('Route files are copied into .reqquest/ before building, so a relative import that leaves src/routes would break:\n' +
|
|
178
|
+
escapes.map(e => ` ${e}`).join('\n') +
|
|
179
|
+
'\nImport through an alias instead: $lib for src/lib, $local for src/local.')
|
|
180
|
+
}
|
|
181
|
+
return forked
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const IMPORT_RE = /(?:\bfrom\s*|\bimport\s*\(\s*|\bimport\s+)(['"])(\.{1,2}\/[^'"]*)\1/g
|
|
185
|
+
|
|
186
|
+
function escapingImports (devRoot, rel, content) {
|
|
187
|
+
if (!/\.(svelte|[cm]?[jt]s)$/.test(rel)) return []
|
|
188
|
+
const found = []
|
|
189
|
+
for (const [, , spec] of content.toString('utf8').matchAll(IMPORT_RE)) {
|
|
190
|
+
const target = resolve(devRoot, dirname(rel), spec)
|
|
191
|
+
if (relative(devRoot, target).startsWith('..')) found.push(`${join('src/routes', rel)}: '${spec}'`)
|
|
192
|
+
}
|
|
193
|
+
return found
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function updateLock (projectRoot, forked, { strict, accept, warnings }) {
|
|
197
|
+
const lockPath = join(projectRoot, LOCKFILE)
|
|
198
|
+
const previous = existsSync(lockPath) ? readJson(lockPath).files ?? {} : {}
|
|
199
|
+
const problems = []
|
|
200
|
+
const next = {}
|
|
201
|
+
|
|
202
|
+
for (const [path, baseHash] of [...forked].sort(([a], [b]) => a.localeCompare(b))) {
|
|
203
|
+
if (!(path in previous)) {
|
|
204
|
+
problems.push(`new override of src/routes/${path} is not recorded`)
|
|
205
|
+
next[path] = baseHash
|
|
206
|
+
} else if (previous[path] !== baseHash && !accept) {
|
|
207
|
+
warnings.push(`ReqQuest changed src/routes/${path} since you overrode it. Compare your copy with ` +
|
|
208
|
+
`node_modules/@reqquest/ui/app/src/routes/${path}, then run \`reqquest-ui sync --accept\`.`)
|
|
209
|
+
problems.push(`src/routes/${path} drifted from its base`)
|
|
210
|
+
next[path] = previous[path] // keep the old hash so the warning repeats until reviewed
|
|
211
|
+
} else {
|
|
212
|
+
next[path] = baseHash
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
for (const path of Object.keys(previous)) {
|
|
216
|
+
if (!forked.has(path)) problems.push(`src/routes/${path} is listed but no longer an override`)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (strict && problems.length) {
|
|
220
|
+
throw new SyncError(`${LOCKFILE} is out of date:\n${problems.map(p => ` ${p}`).join('\n')}\n` +
|
|
221
|
+
'Run `npx reqquest-ui sync` locally (add --accept once you have reviewed any drift) and commit the lockfile.')
|
|
222
|
+
}
|
|
223
|
+
if (JSON.stringify(next) === JSON.stringify(previous)) return
|
|
224
|
+
if (Object.keys(next).length) writeFileSync(lockPath, JSON.stringify({ '//': 'written by `reqquest-ui sync` - commit it', files: next }, null, 2) + '\n')
|
|
225
|
+
else rmSync(lockPath, { force: true })
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function ensureRootTsconfig (projectRoot, warnings) {
|
|
229
|
+
const path = join(projectRoot, 'tsconfig.json')
|
|
230
|
+
const wanted = './.reqquest/tsconfig.json'
|
|
231
|
+
if (!existsSync(path)) {
|
|
232
|
+
writeFileSync(path, JSON.stringify({ extends: wanted }, null, 2) + '\n')
|
|
233
|
+
} else if (!readFileSync(path, 'utf8').includes(wanted)) {
|
|
234
|
+
warnings.push(`tsconfig.json does not extend "${wanted}", so your editor will not resolve $local, $internal or the route types. Replace it with { "extends": "${wanted}" }.`)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Template keys first, project .env overriding by key. */
|
|
239
|
+
function mergeEnv (template, projectEnv) {
|
|
240
|
+
const lines = new Map()
|
|
241
|
+
const add = text => {
|
|
242
|
+
for (const line of text.split('\n')) {
|
|
243
|
+
const m = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(line)
|
|
244
|
+
if (m) lines.set(m[1], line)
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
add(template)
|
|
248
|
+
if (existsSync(projectEnv)) add(readFileSync(projectEnv, 'utf8'))
|
|
249
|
+
return Buffer.from([...lines.values()].join('\n') + '\n')
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Makes appRoot match `files`. Within `managedDirs`, anything not in `files` is deleted; elsewhere
|
|
254
|
+
* (.svelte-kit, node_modules/.vite) is left alone. Generated files are made read-only so an
|
|
255
|
+
* accidental edit fails instead of being silently overwritten by the next sync.
|
|
256
|
+
*/
|
|
257
|
+
function reconcile (appRoot, files, managedDirs) {
|
|
258
|
+
for (const dir of managedDirs) {
|
|
259
|
+
for (const rel of walk(join(appRoot, dir))) {
|
|
260
|
+
if (!files.has(join(dir, rel))) rmSync(join(appRoot, dir, rel), { force: true })
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
for (const [rel, content] of files) {
|
|
264
|
+
const path = join(appRoot, rel)
|
|
265
|
+
if (existsSync(path) && readFileSync(path).equals(content)) continue
|
|
266
|
+
mkdirSync(dirname(path), { recursive: true })
|
|
267
|
+
if (existsSync(path)) chmodSync(path, 0o644)
|
|
268
|
+
writeFileSync(path, content)
|
|
269
|
+
chmodSync(path, 0o444)
|
|
270
|
+
}
|
|
271
|
+
for (const dir of managedDirs) pruneEmptyDirs(join(appRoot, dir))
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function pruneEmptyDirs (dir) {
|
|
275
|
+
if (!existsSync(dir)) return
|
|
276
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
277
|
+
if (entry.isDirectory()) pruneEmptyDirs(join(dir, entry.name))
|
|
278
|
+
}
|
|
279
|
+
if (readdirSync(dir).length === 0) rmSync(dir, { recursive: true })
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** Relative paths of every file under `root`, or [] if it does not exist. */
|
|
283
|
+
function walk (root) {
|
|
284
|
+
if (!existsSync(root) || !statSync(root).isDirectory()) return []
|
|
285
|
+
return readdirSync(root, { recursive: true, withFileTypes: true })
|
|
286
|
+
.filter(e => e.isFile())
|
|
287
|
+
.map(e => relative(root, join(e.parentPath, e.name)))
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function normalizeRoute (route) {
|
|
291
|
+
return route.replace(/^\/+|\/+$/g, '').split('/').join(sep)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function hash (content) {
|
|
295
|
+
return createHash('sha256').update(content).digest('hex').slice(0, 16)
|
|
296
|
+
}
|
package/cli/util.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { dirname, join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Finds an installed package's directory by walking node_modules upward from `from`, the way Node
|
|
6
|
+
* resolves a bare import. Used instead of require.resolve because several of these packages declare
|
|
7
|
+
* "exports" that do not expose package.json.
|
|
8
|
+
*/
|
|
9
|
+
export function packageDir (name, from) {
|
|
10
|
+
let dir = from
|
|
11
|
+
while (true) {
|
|
12
|
+
const candidate = join(dir, 'node_modules', name)
|
|
13
|
+
if (existsSync(join(candidate, 'package.json'))) return candidate
|
|
14
|
+
const parent = dirname(dir)
|
|
15
|
+
if (parent === dir) throw new Error(`Cannot find package '${name}' from ${from}. Is @reqquest/ui installed?`)
|
|
16
|
+
dir = parent
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function readJson (path) {
|
|
21
|
+
return JSON.parse(readFileSync(path, 'utf8'))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Absolute path of a package's executable, from its package.json "bin". */
|
|
25
|
+
export function packageBin (name, from, binName = name.split('/').pop()) {
|
|
26
|
+
const dir = packageDir(name, from)
|
|
27
|
+
const { bin } = readJson(join(dir, 'package.json'))
|
|
28
|
+
return join(dir, typeof bin === 'string' ? bin : bin[binName])
|
|
29
|
+
}
|
package/dist/components.md
CHANGED
|
@@ -5271,10 +5271,6 @@ import TagSkeleton from '@txstate-mws/carbon-svelte/dist/TagSkeleton.svelte'
|
|
|
5271
5271
|
import UserImpersonation from '@txstate-mws/carbon-svelte/dist/UserImpersonation.svelte'
|
|
5272
5272
|
```
|
|
5273
5273
|
|
|
5274
|
-
`@reqquest/ui` has one of these too: `DelayedSkeleton` is compiled into `dist/components/` but is not
|
|
5275
|
-
re-exported from the barrel. The framework's own screens use it via `$lib`; downstream code should
|
|
5276
|
-
register a `loader` on the prompt instead of mounting it directly.
|
|
5277
|
-
|
|
5278
5274
|
### When this file is not enough
|
|
5279
5275
|
|
|
5280
5276
|
- **Props, exactly.** `carbon-svelte` ships unbundled, so
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reqquest/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"overrides": {
|
|
5
5
|
"esrap": "2.3.2"
|
|
6
6
|
},
|
|
@@ -11,8 +11,14 @@
|
|
|
11
11
|
"default": "./dist/index.js"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"reqquest-ui": "bin/reqquest-ui.js"
|
|
16
|
+
},
|
|
14
17
|
"files": [
|
|
15
|
-
"dist"
|
|
18
|
+
"dist",
|
|
19
|
+
"app",
|
|
20
|
+
"bin",
|
|
21
|
+
"cli"
|
|
16
22
|
],
|
|
17
23
|
"scripts": {
|
|
18
24
|
"prepare": "svelte-kit sync",
|
|
@@ -20,40 +26,48 @@
|
|
|
20
26
|
"build": "vite build",
|
|
21
27
|
"preview": "vite preview",
|
|
22
28
|
"package": "svelte-kit sync && svelte-package",
|
|
23
|
-
"prepublishOnly": "npm run package",
|
|
24
29
|
"check": "svelte-check --tsconfig ./tsconfig.json",
|
|
25
30
|
"check:registry": "node check-registry.js",
|
|
26
31
|
"docs:components": "node scripts/build-components-md.js",
|
|
27
32
|
"docs:components:check": "node scripts/build-components-md.js --check",
|
|
28
|
-
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch"
|
|
33
|
+
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
|
|
34
|
+
"prepack": "npm run package && node scripts/pack-app.js"
|
|
29
35
|
},
|
|
30
36
|
"peerDependencies": {
|
|
31
|
-
"@sveltejs/kit": "
|
|
32
|
-
"svelte": "
|
|
37
|
+
"@sveltejs/kit": "2.70.3",
|
|
38
|
+
"@sveltejs/vite-plugin-svelte": "6.2.4",
|
|
39
|
+
"svelte": "5.57.2",
|
|
40
|
+
"vite": "7.3.7"
|
|
33
41
|
},
|
|
34
42
|
"dependencies": {
|
|
43
|
+
"@sveltejs/adapter-static": "3.0.10",
|
|
35
44
|
"@txstate-mws/carbon-svelte": "^1.5.5",
|
|
36
45
|
"@txstate-mws/fastify-shared": "^1.1.0",
|
|
37
46
|
"@txstate-mws/svelte-components": "^1.6.11",
|
|
47
|
+
"@txstate-mws/svelte-forms": "2.1.10",
|
|
38
48
|
"@txstate-mws/sveltekit-utils": "^1.0.2",
|
|
49
|
+
"autoprefixer": "10.6.1",
|
|
50
|
+
"carbon-components-svelte": "0.112.2",
|
|
51
|
+
"carbon-icons-svelte": "13.16.0",
|
|
52
|
+
"carbon-preprocess-svelte": "0.11.49",
|
|
39
53
|
"luxon": "^3.5.0",
|
|
40
|
-
"
|
|
54
|
+
"postcss": "8.5.29",
|
|
55
|
+
"svelte-check": "4.7.6",
|
|
56
|
+
"tailwindcss": "3.4.19",
|
|
57
|
+
"txstate-utils": "^1.8.15",
|
|
58
|
+
"typescript": "5.9.3"
|
|
41
59
|
},
|
|
42
60
|
"devDependencies": {
|
|
43
61
|
"@stylistic/eslint-plugin": "^5.0.0",
|
|
44
|
-
"@sveltejs/
|
|
45
|
-
"@sveltejs/kit": "^2.5.2",
|
|
62
|
+
"@sveltejs/kit": "2.70.3",
|
|
46
63
|
"@sveltejs/package": "^2.0.0",
|
|
47
|
-
"@sveltejs/vite-plugin-svelte": "
|
|
64
|
+
"@sveltejs/vite-plugin-svelte": "6.2.4",
|
|
48
65
|
"@types/luxon": "^3.4.2",
|
|
49
66
|
"@types/node": "^24.3.1",
|
|
50
|
-
"carbon-preprocess-svelte": "~0.11.2",
|
|
51
67
|
"eslint-config-love": "^151.0.0",
|
|
52
68
|
"eslint-plugin-svelte": "^3.0.0",
|
|
53
|
-
"svelte": "
|
|
54
|
-
"
|
|
55
|
-
"typescript": "^5.3.3",
|
|
56
|
-
"vite": "^7.0.0"
|
|
69
|
+
"svelte": "5.57.2",
|
|
70
|
+
"vite": "7.3.7"
|
|
57
71
|
},
|
|
58
72
|
"type": "module"
|
|
59
73
|
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Loader } from "../registry";
|
|
2
|
-
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports & {
|
|
10
|
-
$set?: any;
|
|
11
|
-
$on?: any;
|
|
12
|
-
};
|
|
13
|
-
z_$$bindings?: Bindings;
|
|
14
|
-
}
|
|
15
|
-
declare const DelayedSkeleton: $$__sveltets_2_IsomorphicComponent<{
|
|
16
|
-
loader: Loader;
|
|
17
|
-
}, {
|
|
18
|
-
[evt: string]: CustomEvent<any>;
|
|
19
|
-
}, {}, {}, string>;
|
|
20
|
-
type DelayedSkeleton = InstanceType<typeof DelayedSkeleton>;
|
|
21
|
-
export default DelayedSkeleton;
|