erudit 4.2.0 → 4.3.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/Prose.vue +2 -0
- package/app/components/aside/major/contentNav/items/ContentNavTopic.vue +12 -1
- package/app/components/aside/major/search/SearchResult.vue +16 -2
- package/app/components/aside/minor/contributor/AsideMinorContributor.vue +7 -1
- package/app/components/main/MainStickyHeader.vue +5 -2
- package/app/components/main/MainStickyHeaderPreamble.vue +5 -2
- package/app/components/main/MainTopicPartPage.vue +3 -2
- package/app/components/main/MainTopicPartSwitch.vue +18 -7
- package/app/components/main/connections/Deps.vue +1 -4
- package/app/components/main/connections/MainConnections.vue +9 -3
- package/app/components/main/contentStats/ItemLastChanged.vue +3 -32
- package/app/components/main/contentStats/MainContentStats.vue +3 -4
- package/app/components/preview/Preview.vue +8 -6
- package/app/components/preview/PreviewScreen.vue +9 -7
- package/app/components/preview/screen/Unique.vue +3 -2
- package/app/composables/ads.ts +1 -1
- package/app/composables/analytics.ts +1 -1
- package/app/composables/lastChanged.ts +38 -5
- package/app/composables/og.ts +5 -5
- package/app/composables/scrollUp.ts +3 -1
- package/app/pages/book/[...bookId].vue +3 -2
- package/app/pages/group/[...groupId].vue +3 -2
- package/app/pages/page/[...pageId].vue +4 -2
- package/app/plugins/appSetup/config.ts +1 -0
- package/app/plugins/appSetup/global.ts +3 -0
- package/app/plugins/appSetup/index.ts +4 -1
- package/app/plugins/devReload.client.ts +13 -0
- package/app/router.options.ts +17 -3
- package/app/styles/main.css +2 -2
- package/modules/erudit/dependencies.ts +16 -0
- package/modules/erudit/index.ts +8 -1
- package/modules/erudit/setup/autoImports.ts +143 -0
- package/modules/erudit/setup/elements/globalTemplate.ts +10 -2
- package/modules/erudit/setup/elements/setup.ts +8 -14
- package/modules/erudit/setup/elements/tagsTable.ts +2 -18
- package/modules/erudit/setup/fullRestart.ts +5 -3
- package/modules/erudit/setup/namesTable.ts +33 -0
- package/modules/erudit/setup/problemChecks/setup.ts +60 -0
- package/modules/erudit/setup/problemChecks/shared.ts +4 -0
- package/modules/erudit/setup/problemChecks/template.ts +33 -0
- package/modules/erudit/setup/runtimeConfig.ts +12 -7
- package/nuxt.config.ts +14 -6
- package/package.json +5 -6
- package/server/api/problemScript/[...problemScriptPath].ts +245 -60
- package/server/erudit/build.ts +10 -4
- package/server/erudit/content/nav/build.ts +5 -5
- package/server/erudit/content/nav/front.ts +1 -0
- package/server/erudit/content/repository/deps.ts +33 -3
- package/server/erudit/content/resolve/index.ts +3 -3
- package/server/erudit/content/resolve/utils/contentError.ts +2 -2
- package/server/erudit/content/resolve/utils/insertContentResolved.ts +22 -5
- package/server/erudit/global.ts +5 -1
- package/server/erudit/importer.ts +69 -0
- package/server/erudit/index.ts +2 -2
- package/server/erudit/logger.ts +18 -10
- package/server/erudit/reloadSignal.ts +14 -0
- package/server/routes/_reload.ts +27 -0
- package/shared/types/contentConnections.ts +1 -0
- package/shared/types/frontContentNav.ts +2 -0
package/app/router.options.ts
CHANGED
|
@@ -2,9 +2,23 @@ import type { RouterOptions } from 'vue-router';
|
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
scrollBehavior(_to, _from, savedPosition) {
|
|
5
|
-
if (
|
|
6
|
-
return
|
|
5
|
+
if (savedPosition) {
|
|
6
|
+
return savedPosition;
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
// On a hard reload, _from is START_LOCATION (matched is empty).
|
|
9
|
+
// Return false so the browser's native scroll restoration (history.scrollRestoration = 'auto')
|
|
10
|
+
// can restore the position without Vue Router fighting it with { top: 0 }.
|
|
11
|
+
if (!_from || _from.matched.length === 0) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (_to.query.element) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
// Only scroll to top when the page path actually changes,
|
|
18
|
+
// not for query-param-only replacements (e.g. ?q= from search input).
|
|
19
|
+
if (_to.path === _from.path) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return { top: 0 };
|
|
9
23
|
},
|
|
10
24
|
} as RouterOptions;
|
package/app/styles/main.css
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
--text-main-2xl: calc(1.5 * var(--text-main));
|
|
28
28
|
|
|
29
29
|
--default-transition-timing-function: cubic-bezier(0, 0, 0.5, 1);
|
|
30
|
-
--default-transition-duration: calc(
|
|
30
|
+
--default-transition-duration: calc(180ms * var(--duration-multiplier));
|
|
31
31
|
|
|
32
32
|
--spacing-normal: calc(4 * var(--spacing));
|
|
33
33
|
--spacing-big: calc(2 * var(--spacing-normal));
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
|
|
43
43
|
--h-min-aside-item: 60px;
|
|
44
44
|
|
|
45
|
-
--color-brand: light-dark(#
|
|
45
|
+
--color-brand: light-dark(#00a545, #129adc);
|
|
46
46
|
--color-bg-root: light-dark(#ebebeb, #141414);
|
|
47
47
|
--color-bg-aside: light-dark(#f7f7f7, #1b1b1b);
|
|
48
48
|
--color-bg-main: light-dark(#ffffff, #212121);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Nuxt } from 'nuxt/schema';
|
|
2
|
+
import type { EruditDependencies } from '@erudit-js/core/dependencies';
|
|
3
|
+
|
|
4
|
+
export function addDependencies(
|
|
5
|
+
nuxt: Nuxt,
|
|
6
|
+
dependencies: EruditDependencies | undefined,
|
|
7
|
+
) {
|
|
8
|
+
const transpile = (nuxt.options.build.transpile ||= []);
|
|
9
|
+
const optimizeDeps = nuxt.options.vite.optimizeDeps || {};
|
|
10
|
+
const optimizeDepsInclude = (optimizeDeps.include ||= []);
|
|
11
|
+
|
|
12
|
+
for (const [name, options] of Object.entries(dependencies ?? {})) {
|
|
13
|
+
if (options?.transpile) transpile.push(name);
|
|
14
|
+
if (options?.optimize) optimizeDepsInclude.push(name);
|
|
15
|
+
}
|
|
16
|
+
}
|
package/modules/erudit/index.ts
CHANGED
|
@@ -16,6 +16,9 @@ import {
|
|
|
16
16
|
registerServerGlobals,
|
|
17
17
|
} from './setup/globals';
|
|
18
18
|
import { setupProseElements } from './setup/elements/setup';
|
|
19
|
+
import { setupProblemChecks } from './setup/problemChecks/setup';
|
|
20
|
+
import { setupAutoImports } from './setup/autoImports';
|
|
21
|
+
import { addDependencies } from './dependencies';
|
|
19
22
|
|
|
20
23
|
export default defineNuxtModule({
|
|
21
24
|
meta: { name: 'Erudit', configKey: 'erudit', version },
|
|
@@ -27,12 +30,16 @@ export default defineNuxtModule({
|
|
|
27
30
|
await registerServerGlobals();
|
|
28
31
|
await registerGlobalContentTypes();
|
|
29
32
|
|
|
30
|
-
const { eruditRuntimeConfig, nuxtAugmentations } =
|
|
33
|
+
const { eruditConfig, eruditRuntimeConfig, nuxtAugmentations } =
|
|
31
34
|
await setupEruditRuntimeConfig(nuxt);
|
|
32
35
|
await setupWatchers(nuxt);
|
|
33
36
|
await setupEruditFullRestart(nuxt);
|
|
34
37
|
await setupEruditPublicAssets(nuxt);
|
|
35
38
|
await setupProseElements(nuxt, eruditRuntimeConfig);
|
|
39
|
+
await setupProblemChecks(nuxt, eruditConfig);
|
|
40
|
+
await setupAutoImports(nuxt, eruditConfig);
|
|
41
|
+
|
|
42
|
+
addDependencies(nuxt, eruditConfig.dependencies);
|
|
36
43
|
|
|
37
44
|
if (nuxtAugmentations) {
|
|
38
45
|
for (const augment of nuxtAugmentations) {
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { writeFileSync } from 'node:fs';
|
|
2
|
+
import type { Nuxt } from 'nuxt/schema';
|
|
3
|
+
import { addTemplate, findPath } from 'nuxt/kit';
|
|
4
|
+
import { sn } from 'unslash';
|
|
5
|
+
import type { EruditConfig } from '@erudit-js/core/eruditConfig/config';
|
|
6
|
+
|
|
7
|
+
import { PROJECT_PATH } from '../env';
|
|
8
|
+
import { moduleLogger } from '../logger';
|
|
9
|
+
import { printGrayNamesTable } from './namesTable';
|
|
10
|
+
|
|
11
|
+
interface ResolvedAutoImport {
|
|
12
|
+
/** Config path as written by the user (e.g. './my-globals') */
|
|
13
|
+
configPath: string;
|
|
14
|
+
/** Absolute resolved path to the source file */
|
|
15
|
+
absPath: string;
|
|
16
|
+
/** #project/ relative path for TypeScript type declarations */
|
|
17
|
+
projectRelativePath: string;
|
|
18
|
+
/** Named export identifiers discovered from the file */
|
|
19
|
+
exportNames: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function setupAutoImports(nuxt: Nuxt, eruditConfig: EruditConfig) {
|
|
23
|
+
const autoImportPaths = eruditConfig.autoImports ?? [];
|
|
24
|
+
|
|
25
|
+
if (autoImportPaths.length === 0) {
|
|
26
|
+
createEmptyTemplate(nuxt);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const resolved: ResolvedAutoImport[] = [];
|
|
31
|
+
|
|
32
|
+
for (const configPath of autoImportPaths) {
|
|
33
|
+
const absPath = await findPath(configPath, {
|
|
34
|
+
cwd: PROJECT_PATH,
|
|
35
|
+
extensions: ['.ts', '.js'],
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (!absPath) {
|
|
39
|
+
throw new Error(`[autoImports] Failed to resolve path "${configPath}"!`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Discover named exports by dynamically importing the file
|
|
43
|
+
const mod = await import(absPath);
|
|
44
|
+
const exportNames = Object.keys(mod).filter((key) => key !== 'default');
|
|
45
|
+
|
|
46
|
+
if (exportNames.length === 0) {
|
|
47
|
+
moduleLogger.warn(
|
|
48
|
+
`[autoImports] File "${configPath}" has no named exports — skipping.`,
|
|
49
|
+
);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Compute #project/ relative path for TypeScript type declarations
|
|
54
|
+
const normalizedAbsPath = absPath.replace(/\\/g, '/');
|
|
55
|
+
const normalizedProjectPath = PROJECT_PATH.replace(/\\/g, '/');
|
|
56
|
+
const projectRelativePath = normalizedAbsPath
|
|
57
|
+
.replace(normalizedProjectPath + '/', '')
|
|
58
|
+
.replace(/\.(ts|js)$/, '');
|
|
59
|
+
|
|
60
|
+
resolved.push({
|
|
61
|
+
configPath,
|
|
62
|
+
absPath: normalizedAbsPath,
|
|
63
|
+
projectRelativePath,
|
|
64
|
+
exportNames,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const allExportNames = resolved.flatMap((r) => r.exportNames);
|
|
69
|
+
|
|
70
|
+
createTemplate(nuxt, resolved, allExportNames);
|
|
71
|
+
createTypeDeclarations(resolved);
|
|
72
|
+
|
|
73
|
+
moduleLogger.success(
|
|
74
|
+
`Registered ${allExportNames.length} auto-import(s) from ${resolved.length} file(s)!`,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
printGrayNamesTable(allExportNames);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function createEmptyTemplate(nuxt: Nuxt) {
|
|
81
|
+
addTemplate({
|
|
82
|
+
write: true,
|
|
83
|
+
filename: '#erudit/autoImports.ts',
|
|
84
|
+
getContents: () =>
|
|
85
|
+
`export const autoImportNames = new Set<string>();\nexport function registerAutoImportGlobals() { (globalThis as any).ERUDIT_GLOBAL = (globalThis as any).ERUDIT_GLOBAL || {}; }\n`,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const alias = (nuxt.options.alias ||= {});
|
|
89
|
+
alias['#erudit/autoImports'] =
|
|
90
|
+
nuxt.options.buildDir + '/#erudit/autoImports.ts';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function createTemplate(
|
|
94
|
+
nuxt: Nuxt,
|
|
95
|
+
resolved: ResolvedAutoImport[],
|
|
96
|
+
allExportNames: string[],
|
|
97
|
+
) {
|
|
98
|
+
const importStatements = resolved
|
|
99
|
+
.map((r) => {
|
|
100
|
+
const names = r.exportNames.join(', ');
|
|
101
|
+
const importPath = r.absPath.replace(/\.(ts|js)$/, '');
|
|
102
|
+
return `import { ${names} } from '${importPath}';`;
|
|
103
|
+
})
|
|
104
|
+
.join('\n');
|
|
105
|
+
|
|
106
|
+
const template =
|
|
107
|
+
`
|
|
108
|
+
${importStatements}
|
|
109
|
+
|
|
110
|
+
export const autoImportNames = new Set<string>(${JSON.stringify(allExportNames)});
|
|
111
|
+
|
|
112
|
+
export function registerAutoImportGlobals() {
|
|
113
|
+
(globalThis as any).ERUDIT_GLOBAL = (globalThis as any).ERUDIT_GLOBAL || {};
|
|
114
|
+
Object.assign((globalThis as any).ERUDIT_GLOBAL, {
|
|
115
|
+
${allExportNames.join(',\n ')}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
`.trim() + '\n';
|
|
119
|
+
|
|
120
|
+
addTemplate({
|
|
121
|
+
write: true,
|
|
122
|
+
filename: '#erudit/autoImports.ts',
|
|
123
|
+
getContents: () => template,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const alias = (nuxt.options.alias ||= {});
|
|
127
|
+
alias['#erudit/autoImports'] =
|
|
128
|
+
nuxt.options.buildDir + '/#erudit/autoImports.ts';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function createTypeDeclarations(resolved: ResolvedAutoImport[]) {
|
|
132
|
+
let dts = 'export {}\n\ndeclare global {\n';
|
|
133
|
+
|
|
134
|
+
for (const r of resolved) {
|
|
135
|
+
for (const name of r.exportNames) {
|
|
136
|
+
dts += ` const ${name}: typeof import('#project/${r.projectRelativePath}')['${name}']\n`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
dts += '}\n';
|
|
141
|
+
|
|
142
|
+
writeFileSync(sn(PROJECT_PATH, '.erudit/types/autoImports.d.ts'), dts);
|
|
143
|
+
}
|
|
@@ -53,17 +53,25 @@ export const elementsGlobals = {
|
|
|
53
53
|
.join(',\n ')}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
export const eruditGlobalNames = new Set<string>([
|
|
57
|
+
...Object.values(coreElements).flatMap((el: any) => (el.tags ?? []).map((t: any) => String(t.tagName))),
|
|
58
|
+
...Object.keys(elementsGlobals),
|
|
59
|
+
'jsx', 'jsxs', 'Fragment', 'defineProblemScript',
|
|
60
|
+
]);
|
|
61
|
+
|
|
56
62
|
export function registerProseGlobals() {
|
|
63
|
+
(globalThis as any).ERUDIT_GLOBAL = (globalThis as any).ERUDIT_GLOBAL || {};
|
|
64
|
+
|
|
57
65
|
for (const coreElement of Object.values(coreElements)) {
|
|
58
66
|
const tags = coreElement.tags || [];
|
|
59
67
|
for (const tag of tags) {
|
|
60
|
-
Object.assign(globalThis, {
|
|
68
|
+
Object.assign((globalThis as any).ERUDIT_GLOBAL, {
|
|
61
69
|
[tag.tagName]: tag,
|
|
62
70
|
});
|
|
63
71
|
}
|
|
64
72
|
}
|
|
65
73
|
|
|
66
|
-
Object.assign(globalThis, {
|
|
74
|
+
Object.assign((globalThis as any).ERUDIT_GLOBAL, {
|
|
67
75
|
// Make jsx runtime globally available (for prose generation in isolated modules like problem scripts)
|
|
68
76
|
jsx,
|
|
69
77
|
jsxs,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
1
|
import type { Nuxt } from 'nuxt/schema';
|
|
3
2
|
import { findPath } from 'nuxt/kit';
|
|
4
3
|
|
|
@@ -6,12 +5,13 @@ import type { ProseCoreElement } from '@erudit-js/prose';
|
|
|
6
5
|
|
|
7
6
|
import type { EruditRuntimeConfig } from '../../../../shared/types/runtimeConfig';
|
|
8
7
|
import { moduleLogger } from '../../logger';
|
|
8
|
+
import { printGrayNamesTable } from '../namesTable';
|
|
9
9
|
import type { ElementData } from './shared';
|
|
10
|
-
import { createTagsTable } from './tagsTable';
|
|
11
10
|
import { createElementGlobalTypes } from './elementGlobalTypes';
|
|
12
11
|
import { createGlobalTemplate } from './globalTemplate';
|
|
13
12
|
import { createAppTemplate } from './appTemplate';
|
|
14
13
|
import { PROJECT_PATH } from '../../env';
|
|
14
|
+
import { addDependencies } from '../../dependencies';
|
|
15
15
|
|
|
16
16
|
const BUILTIN_ELEMENT_PATHS = [
|
|
17
17
|
'@erudit-js/prose/elements/callout',
|
|
@@ -131,16 +131,7 @@ export async function setupProseElements(
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
const optimizeDeps = nuxt.options.vite.optimizeDeps || {};
|
|
136
|
-
const optimizeDepsInclude = (optimizeDeps.include ||= []);
|
|
137
|
-
|
|
138
|
-
for (const [name, options] of Object.entries(
|
|
139
|
-
coreElement.dependencies ?? {},
|
|
140
|
-
)) {
|
|
141
|
-
if (options?.transpile) transpile.push(name);
|
|
142
|
-
if (options?.optimize) optimizeDepsInclude.push(name);
|
|
143
|
-
}
|
|
134
|
+
addDependencies(nuxt, coreElement.dependencies);
|
|
144
135
|
}
|
|
145
136
|
|
|
146
137
|
elementsData.push(elementData);
|
|
@@ -160,6 +151,9 @@ Registered ${elementsNumber} prose elements: ${schemasNumber} schema(s) and ${ta
|
|
|
160
151
|
`.trim(),
|
|
161
152
|
);
|
|
162
153
|
|
|
163
|
-
const
|
|
164
|
-
|
|
154
|
+
const tagNames = elementsData.flatMap((data) =>
|
|
155
|
+
data.coreElements.flatMap((coreElement) => Object.keys(coreElement.tags)),
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
printGrayNamesTable(tagNames.map((t) => `<${t}>`));
|
|
165
159
|
}
|
|
@@ -1,28 +1,12 @@
|
|
|
1
1
|
import type { ElementData } from './shared';
|
|
2
|
+
import { createNamesTable } from '../namesTable';
|
|
2
3
|
|
|
3
4
|
export function createTagsTable(elementsData: ElementData[], columns = 4) {
|
|
4
5
|
const tagNames = elementsData.flatMap((data) =>
|
|
5
6
|
data.coreElements.flatMap((coreElement) => Object.keys(coreElement.tags)),
|
|
6
7
|
);
|
|
7
8
|
|
|
8
|
-
if (tagNames.length === 0) return '';
|
|
9
|
-
|
|
10
|
-
const cols = Math.max(1, columns);
|
|
11
9
|
const formatted = tagNames.map((t) => `<${t}>`);
|
|
12
|
-
const maxLen = Math.max(...formatted.map((s) => s.length));
|
|
13
|
-
const colWidth = maxLen + 2; // padding between columns
|
|
14
|
-
|
|
15
|
-
const rows = Math.ceil(formatted.length / cols);
|
|
16
|
-
const lines: string[] = [];
|
|
17
|
-
|
|
18
|
-
for (let r = 0; r < rows; r++) {
|
|
19
|
-
const start = r * cols;
|
|
20
|
-
const rowItems = formatted.slice(start, start + cols);
|
|
21
|
-
const padded = rowItems.map((s) => s.padEnd(colWidth, ' '));
|
|
22
|
-
lines.push(padded.join('').replace(/\s+$/u, '')); // trim trailing spaces on the row
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const tagTable = lines.join('\n');
|
|
26
10
|
|
|
27
|
-
return
|
|
11
|
+
return createNamesTable(formatted, columns);
|
|
28
12
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Nuxt } from '@nuxt/schema';
|
|
2
2
|
import { debounce } from 'perfect-debounce';
|
|
3
|
-
import
|
|
3
|
+
import { styleText } from 'node:util';
|
|
4
4
|
import { sn } from 'unslash';
|
|
5
5
|
|
|
6
6
|
import { ERUDIT_PACKAGE_WATCHER, ERUDIT_PROJECT_WATCHER } from '../watcher';
|
|
@@ -15,8 +15,10 @@ export async function setupEruditFullRestart(nuxt: Nuxt) {
|
|
|
15
15
|
changedPaths.clear();
|
|
16
16
|
|
|
17
17
|
moduleLogger.warn(
|
|
18
|
-
`${
|
|
19
|
-
files
|
|
18
|
+
`${styleText('yellow', 'Full restart due to critical file change(s):')}\n\n` +
|
|
19
|
+
files
|
|
20
|
+
.map((p, i) => styleText('gray', `${i + 1} -`) + ` "${p}"`)
|
|
21
|
+
.join('\n'),
|
|
20
22
|
);
|
|
21
23
|
|
|
22
24
|
await nuxt.callHook('close', nuxt);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
|
+
|
|
3
|
+
export function createNamesTable(names: string[], columns = 4) {
|
|
4
|
+
if (names.length === 0) return '';
|
|
5
|
+
|
|
6
|
+
const cols = Math.max(1, columns);
|
|
7
|
+
const maxLen = Math.max(...names.map((s) => s.length));
|
|
8
|
+
const colWidth = maxLen + 2;
|
|
9
|
+
|
|
10
|
+
const rows = Math.ceil(names.length / cols);
|
|
11
|
+
const lines: string[] = [];
|
|
12
|
+
|
|
13
|
+
for (let r = 0; r < rows; r++) {
|
|
14
|
+
const start = r * cols;
|
|
15
|
+
const rowItems = names.slice(start, start + cols);
|
|
16
|
+
const padded = rowItems.map((s) => s.padEnd(colWidth, ' '));
|
|
17
|
+
lines.push(padded.join('').replace(/\s+$/u, ''));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return lines.join('\n');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function printGrayNamesTable(names: string[], columns = 4) {
|
|
24
|
+
const table = createNamesTable(names, columns);
|
|
25
|
+
if (!table) return;
|
|
26
|
+
|
|
27
|
+
console.log(
|
|
28
|
+
table
|
|
29
|
+
.split('\n')
|
|
30
|
+
.map((line) => styleText('gray', line))
|
|
31
|
+
.join('\n'),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Nuxt } from 'nuxt/schema';
|
|
2
|
+
import { findPath } from 'nuxt/kit';
|
|
3
|
+
import type { EruditConfig } from '@erudit-js/core/eruditConfig/config';
|
|
4
|
+
import type { ProblemChecker } from '@erudit-js/core/problemCheck';
|
|
5
|
+
|
|
6
|
+
import type { ResolvedProblemCheck } from './shared';
|
|
7
|
+
import { PROJECT_PATH } from '../../env';
|
|
8
|
+
import { moduleLogger } from '../../logger';
|
|
9
|
+
import { printGrayNamesTable } from '../namesTable';
|
|
10
|
+
import { createTemplate } from './template';
|
|
11
|
+
|
|
12
|
+
export async function setupProblemChecks(
|
|
13
|
+
nuxt: Nuxt,
|
|
14
|
+
eruditConfig: EruditConfig,
|
|
15
|
+
) {
|
|
16
|
+
const resolvedProblemChecks: ResolvedProblemCheck[] = [];
|
|
17
|
+
const seenProblemChecks = new Set<string>();
|
|
18
|
+
|
|
19
|
+
for (const strProblemCheck of eruditConfig.problemChecks ?? []) {
|
|
20
|
+
const absPath = await findPath(strProblemCheck, {
|
|
21
|
+
cwd: PROJECT_PATH,
|
|
22
|
+
extensions: ['.ts', '.js'],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (!absPath) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`Failed to resolve path for problem check "${strProblemCheck}"!`,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const defaultExport = (await import(absPath)).default as ProblemChecker;
|
|
32
|
+
const name = defaultExport?.name;
|
|
33
|
+
|
|
34
|
+
if (!name) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Problem check at "${strProblemCheck}" does not have a name!`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (seenProblemChecks.has(name)) {
|
|
41
|
+
throw new Error(`Duplicate problem check name "${name}" found!`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
seenProblemChecks.add(name);
|
|
45
|
+
resolvedProblemChecks.push({
|
|
46
|
+
name,
|
|
47
|
+
absPath,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
createTemplate(nuxt, resolvedProblemChecks);
|
|
52
|
+
|
|
53
|
+
if (resolvedProblemChecks.length > 0) {
|
|
54
|
+
moduleLogger.success(
|
|
55
|
+
`Registered ${resolvedProblemChecks.length} problem check(s)!`,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
printGrayNamesTable(resolvedProblemChecks.map((c) => c.name));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Nuxt } from 'nuxt/schema';
|
|
2
|
+
import { addTemplate } from 'nuxt/kit';
|
|
3
|
+
|
|
4
|
+
import type { ResolvedProblemCheck } from './shared';
|
|
5
|
+
|
|
6
|
+
export function createTemplate(
|
|
7
|
+
nuxt: Nuxt,
|
|
8
|
+
problemChecks: ResolvedProblemCheck[],
|
|
9
|
+
) {
|
|
10
|
+
const template = `
|
|
11
|
+
import type { ProblemCheckers } from '@erudit-js/core/problemCheck';
|
|
12
|
+
|
|
13
|
+
${problemChecks
|
|
14
|
+
.map(
|
|
15
|
+
(check) =>
|
|
16
|
+
`import ${check.name} from '${check.absPath.replace(/\.(ts|js)$/, '')}';`,
|
|
17
|
+
)
|
|
18
|
+
.join('\n')}
|
|
19
|
+
|
|
20
|
+
export const problemCheckers: ProblemCheckers = {
|
|
21
|
+
${problemChecks.map((check) => `${check.name},`).join('\n ')}
|
|
22
|
+
}
|
|
23
|
+
`.trim();
|
|
24
|
+
|
|
25
|
+
addTemplate({
|
|
26
|
+
write: true,
|
|
27
|
+
filename: '#erudit/checks.ts',
|
|
28
|
+
getContents: () => template,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const alias = (nuxt.options.alias ||= {});
|
|
32
|
+
alias['#erudit/checks'] = nuxt.options.buildDir + '/#erudit/checks.ts';
|
|
33
|
+
}
|
|
@@ -2,8 +2,9 @@ import { existsSync } from 'node:fs';
|
|
|
2
2
|
import type { Nuxt } from '@nuxt/schema';
|
|
3
3
|
import { sn } from 'unslash';
|
|
4
4
|
import type { EruditConfig } from '@erudit-js/core/eruditConfig/config';
|
|
5
|
+
import { isDevLikeMode } from '@erudit-js/core/mode';
|
|
5
6
|
|
|
6
|
-
import { PROJECT_PATH } from '../env.js';
|
|
7
|
+
import { ERUDIT_MODE, PROJECT_PATH } from '../env.js';
|
|
7
8
|
import { moduleLogger } from '../logger.js';
|
|
8
9
|
import type {
|
|
9
10
|
EruditPublicRuntimeConfig,
|
|
@@ -26,25 +27,28 @@ export async function setupEruditRuntimeConfig(nuxt: Nuxt) {
|
|
|
26
27
|
// Erudit Runtime Config
|
|
27
28
|
//
|
|
28
29
|
|
|
29
|
-
nuxt.options.runtimeConfig.erudit = {
|
|
30
|
+
nuxt.options.runtimeConfig.erudit = (<EruditRuntimeConfig>{
|
|
30
31
|
elements: eruditConfig.elements || [],
|
|
31
32
|
countElements: eruditConfig.countElements || [],
|
|
32
33
|
indexPage: eruditConfig.indexPage,
|
|
33
|
-
} satisfies EruditRuntimeConfig;
|
|
34
|
+
}) satisfies EruditRuntimeConfig;
|
|
34
35
|
|
|
35
36
|
//
|
|
36
37
|
// Erudit Public Runtime Config
|
|
37
38
|
//
|
|
38
39
|
|
|
39
|
-
nuxt.options.runtimeConfig.public.erudit = {
|
|
40
|
+
nuxt.options.runtimeConfig.public.erudit = (<EruditPublicRuntimeConfig>{
|
|
40
41
|
debug: {
|
|
41
42
|
ads: eruditConfig.debug?.ads ?? false,
|
|
42
43
|
log: eruditConfig.debug?.log ?? false,
|
|
43
44
|
slowTransition: eruditConfig.debug?.slowTransition ?? false,
|
|
44
45
|
fakeApi: {
|
|
45
|
-
repository:
|
|
46
|
+
repository:
|
|
47
|
+
eruditConfig.debug?.fakeApi?.repository ??
|
|
48
|
+
(nuxt.options.dev || isDevLikeMode(ERUDIT_MODE)),
|
|
46
49
|
lastChanged:
|
|
47
|
-
eruditConfig.debug?.fakeApi?.lastChanged ??
|
|
50
|
+
eruditConfig.debug?.fakeApi?.lastChanged ??
|
|
51
|
+
(nuxt.options.dev || isDevLikeMode(ERUDIT_MODE)),
|
|
48
52
|
},
|
|
49
53
|
analytics: eruditConfig.debug?.analytics,
|
|
50
54
|
},
|
|
@@ -85,7 +89,7 @@ export async function setupEruditRuntimeConfig(nuxt: Nuxt) {
|
|
|
85
89
|
sponsors: eruditConfig.sponsors,
|
|
86
90
|
ads: eruditConfig.ads,
|
|
87
91
|
analytics: eruditConfig.analytics,
|
|
88
|
-
} satisfies EruditPublicRuntimeConfig;
|
|
92
|
+
}) satisfies EruditPublicRuntimeConfig;
|
|
89
93
|
|
|
90
94
|
//
|
|
91
95
|
// Other
|
|
@@ -94,6 +98,7 @@ export async function setupEruditRuntimeConfig(nuxt: Nuxt) {
|
|
|
94
98
|
nuxt.options.runtimeConfig.public.buildTime = Date.now();
|
|
95
99
|
|
|
96
100
|
return {
|
|
101
|
+
eruditConfig,
|
|
97
102
|
eruditRuntimeConfig: nuxt.options.runtimeConfig
|
|
98
103
|
.erudit as EruditRuntimeConfig,
|
|
99
104
|
eruditPublicRuntimeConfig: nuxt.options.runtimeConfig.public
|
package/nuxt.config.ts
CHANGED
|
@@ -3,11 +3,6 @@ import { sn } from 'unslash';
|
|
|
3
3
|
|
|
4
4
|
import { BASE_URL, ERUDIT_COMMAND, PROJECT_PATH } from './modules/erudit/env';
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* This is context-unaware or "static" Nuxt configuration.
|
|
8
|
-
* The only thing that works here are aliases.
|
|
9
|
-
* If you need to use context (e.g. paths to package/project or Erudit project config), use `./modules/erudit/setup/nuxtConfig.ts` file.
|
|
10
|
-
*/
|
|
11
6
|
export default defineNuxtConfig({
|
|
12
7
|
compatibilityDate: '2026-01-01',
|
|
13
8
|
devtools: { enabled: true },
|
|
@@ -18,6 +13,11 @@ export default defineNuxtConfig({
|
|
|
18
13
|
iconsDir: '#layers/erudit/app/assets/icons',
|
|
19
14
|
},
|
|
20
15
|
plugins: ['#layers/erudit/app/plugins/appSetup'],
|
|
16
|
+
typescript: {
|
|
17
|
+
nodeTsConfig: {
|
|
18
|
+
include: [sn(PROJECT_PATH, 'packages/erudit/modules/erudit/**/*.ts')],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
21
|
runtimeConfig: {
|
|
22
22
|
eruditPath: '',
|
|
23
23
|
projectPath: '',
|
|
@@ -25,6 +25,7 @@ export default defineNuxtConfig({
|
|
|
25
25
|
public: {
|
|
26
26
|
eruditVersion: '',
|
|
27
27
|
eruditMode: '',
|
|
28
|
+
eruditReload: true,
|
|
28
29
|
siteUrl: '',
|
|
29
30
|
},
|
|
30
31
|
},
|
|
@@ -93,7 +94,14 @@ export default defineNuxtConfig({
|
|
|
93
94
|
},
|
|
94
95
|
],
|
|
95
96
|
optimizeDeps: {
|
|
96
|
-
|
|
97
|
+
include: [
|
|
98
|
+
'@vue/devtools-core',
|
|
99
|
+
'@vue/devtools-kit',
|
|
100
|
+
'@floating-ui/vue',
|
|
101
|
+
'unslash',
|
|
102
|
+
'tsprose',
|
|
103
|
+
'tsprose/jsx-runtime',
|
|
104
|
+
],
|
|
97
105
|
},
|
|
98
106
|
server: {
|
|
99
107
|
fs: { strict: false },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "erudit",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0-dev.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "🤓 CMS for perfect educational sites.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,15 +24,14 @@
|
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@erudit-js/cli": "4.
|
|
28
|
-
"@erudit-js/core": "4.
|
|
29
|
-
"@erudit-js/prose": "4.
|
|
27
|
+
"@erudit-js/cli": "4.3.0-dev.1",
|
|
28
|
+
"@erudit-js/core": "4.3.0-dev.1",
|
|
29
|
+
"@erudit-js/prose": "4.3.0-dev.1",
|
|
30
30
|
"unslash": "^2.0.0",
|
|
31
31
|
"@floating-ui/vue": "^1.1.10",
|
|
32
|
-
"tsprose": "^1.0.
|
|
32
|
+
"tsprose": "^1.0.1",
|
|
33
33
|
"@tailwindcss/vite": "^4.2.0",
|
|
34
34
|
"better-sqlite3": "^12.6.2",
|
|
35
|
-
"chalk": "^5.6.2",
|
|
36
35
|
"chokidar": "^5.0.0",
|
|
37
36
|
"consola": "^3.4.2",
|
|
38
37
|
"drizzle-kit": "^0.31.9",
|