@amamo/mdx 0.1.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/LICENSE +21 -0
- package/README.md +120 -0
- package/dist/compiler.d.ts +28 -0
- package/dist/compiler.js +446 -0
- package/dist/config.d.ts +123 -0
- package/dist/config.js +134 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +2 -0
- package/dist/native.d.ts +71 -0
- package/dist/native.js +68 -0
- package/dist/next-loader.cjs +33 -0
- package/dist/next.d.ts +8 -0
- package/dist/next.js +64 -0
- package/dist/shiki.d.ts +7 -0
- package/dist/shiki.js +82 -0
- package/dist/vite.d.ts +3 -0
- package/dist/vite.js +100 -0
- package/native.cjs +39 -0
- package/native.d.ts +12 -0
- package/package.json +124 -0
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
export type JsonValue = null | boolean | number | string | JsonValue[] | {
|
|
2
|
+
[key: string]: JsonValue;
|
|
3
|
+
};
|
|
4
|
+
export type ManifestField = string | {
|
|
5
|
+
default?: JsonValue;
|
|
6
|
+
from: string;
|
|
7
|
+
transform?: 'exists' | 'mediaUrl' | 'sha256';
|
|
8
|
+
};
|
|
9
|
+
export interface ILocaleConfig {
|
|
10
|
+
default: string;
|
|
11
|
+
names: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface ISlugConfig {
|
|
14
|
+
indexNames?: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface ICollectionConfig {
|
|
17
|
+
directory: string;
|
|
18
|
+
extensions?: string[];
|
|
19
|
+
locales?: ILocaleConfig;
|
|
20
|
+
schema: {
|
|
21
|
+
[key: string]: JsonValue;
|
|
22
|
+
};
|
|
23
|
+
sensitive?: string[];
|
|
24
|
+
slug?: ISlugConfig;
|
|
25
|
+
}
|
|
26
|
+
export interface IMdxConfig {
|
|
27
|
+
gfm?: boolean;
|
|
28
|
+
hardBreaks?: boolean;
|
|
29
|
+
jsxImportSource?: string;
|
|
30
|
+
providerImportSource?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface IHighlightConfig {
|
|
33
|
+
colorReplacements?: Record<string, string>;
|
|
34
|
+
engine?: 'javascript' | 'oniguruma';
|
|
35
|
+
languages?: 'auto' | string[];
|
|
36
|
+
provider: 'shiki';
|
|
37
|
+
themes: {
|
|
38
|
+
dark: string;
|
|
39
|
+
light: string;
|
|
40
|
+
};
|
|
41
|
+
unknownLanguage?: 'error' | 'plain';
|
|
42
|
+
}
|
|
43
|
+
export interface IMediaConfig {
|
|
44
|
+
attributes?: Record<string, string[]>;
|
|
45
|
+
missing?: 'error' | 'warn';
|
|
46
|
+
}
|
|
47
|
+
export interface IDerivedConfig {
|
|
48
|
+
lastModified?: boolean;
|
|
49
|
+
readingTime?: boolean;
|
|
50
|
+
}
|
|
51
|
+
export interface IManifestConfig {
|
|
52
|
+
collections?: string[];
|
|
53
|
+
fields: Record<string, ManifestField>;
|
|
54
|
+
key?: string;
|
|
55
|
+
output: string;
|
|
56
|
+
sort?: Array<{
|
|
57
|
+
direction?: 'asc' | 'desc';
|
|
58
|
+
field: string;
|
|
59
|
+
}>;
|
|
60
|
+
}
|
|
61
|
+
export interface ICacheConfig {
|
|
62
|
+
directory?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface IAmamoMdxConfig {
|
|
65
|
+
cache?: false | ICacheConfig;
|
|
66
|
+
collections: Record<string, ICollectionConfig>;
|
|
67
|
+
derived?: IDerivedConfig;
|
|
68
|
+
generatedDirectory?: string;
|
|
69
|
+
highlight?: false | IHighlightConfig;
|
|
70
|
+
manifests?: Record<string, IManifestConfig>;
|
|
71
|
+
mdx?: IMdxConfig;
|
|
72
|
+
media?: false | IMediaConfig;
|
|
73
|
+
root?: string;
|
|
74
|
+
}
|
|
75
|
+
export interface INormalizedCollectionConfig {
|
|
76
|
+
directory: string;
|
|
77
|
+
extensions: string[];
|
|
78
|
+
locales?: ILocaleConfig;
|
|
79
|
+
schema: {
|
|
80
|
+
[key: string]: JsonValue;
|
|
81
|
+
};
|
|
82
|
+
sensitive: string[];
|
|
83
|
+
slug: {
|
|
84
|
+
indexNames: string[];
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export interface INormalizedHighlightConfig {
|
|
88
|
+
colorReplacements: Record<string, string>;
|
|
89
|
+
enabled: boolean;
|
|
90
|
+
engine: 'javascript' | 'oniguruma';
|
|
91
|
+
languages: 'auto' | string[];
|
|
92
|
+
provider: 'shiki';
|
|
93
|
+
themes: {
|
|
94
|
+
dark: string;
|
|
95
|
+
light: string;
|
|
96
|
+
};
|
|
97
|
+
unknownLanguage: 'error' | 'plain';
|
|
98
|
+
}
|
|
99
|
+
export interface INormalizedMediaConfig {
|
|
100
|
+
attributes: Record<string, string[]>;
|
|
101
|
+
enabled: boolean;
|
|
102
|
+
missing: 'error' | 'warn';
|
|
103
|
+
}
|
|
104
|
+
export interface INormalizedManifestConfig extends Omit<IManifestConfig, 'collections' | 'output'> {
|
|
105
|
+
collections: string[];
|
|
106
|
+
output: string;
|
|
107
|
+
}
|
|
108
|
+
export interface INormalizedConfig {
|
|
109
|
+
cache: {
|
|
110
|
+
directory: string;
|
|
111
|
+
enabled: boolean;
|
|
112
|
+
};
|
|
113
|
+
collections: Record<string, INormalizedCollectionConfig>;
|
|
114
|
+
derived: Required<IDerivedConfig>;
|
|
115
|
+
generatedDirectory: string;
|
|
116
|
+
highlight: INormalizedHighlightConfig;
|
|
117
|
+
manifests: Record<string, INormalizedManifestConfig>;
|
|
118
|
+
mdx: Required<IMdxConfig>;
|
|
119
|
+
media: INormalizedMediaConfig;
|
|
120
|
+
root: string;
|
|
121
|
+
}
|
|
122
|
+
export declare function defineConfig<T extends IAmamoMdxConfig>(config: T): T;
|
|
123
|
+
export declare function normalizeConfig(config: IAmamoMdxConfig): INormalizedConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const DEFAULT_MEDIA_ATTRIBUTES = {
|
|
4
|
+
audio: ['src'],
|
|
5
|
+
embed: ['src'],
|
|
6
|
+
img: ['src', 'srcset'],
|
|
7
|
+
object: ['data'],
|
|
8
|
+
source: ['src', 'srcset'],
|
|
9
|
+
track: ['src'],
|
|
10
|
+
video: ['src', 'poster'],
|
|
11
|
+
};
|
|
12
|
+
function notSerializable(location, reason) {
|
|
13
|
+
throw new TypeError(`AMAMO_CONFIG_NOT_SERIALIZABLE: ${location} ${reason}`);
|
|
14
|
+
}
|
|
15
|
+
function assertPlainData(value, location, active) {
|
|
16
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean')
|
|
17
|
+
return;
|
|
18
|
+
if (typeof value === 'number') {
|
|
19
|
+
if (!Number.isFinite(value))
|
|
20
|
+
notSerializable(location, 'must be a finite number');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (typeof value !== 'object')
|
|
24
|
+
notSerializable(location, `contains ${typeof value}`);
|
|
25
|
+
if (active.has(value))
|
|
26
|
+
notSerializable(location, 'contains a cycle');
|
|
27
|
+
const prototype = Object.getPrototypeOf(value);
|
|
28
|
+
if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) {
|
|
29
|
+
notSerializable(location, 'must be a plain object');
|
|
30
|
+
}
|
|
31
|
+
active.add(value);
|
|
32
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
33
|
+
if (typeof key === 'symbol')
|
|
34
|
+
notSerializable(location, 'contains a symbol key');
|
|
35
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
36
|
+
if (!descriptor || !('value' in descriptor))
|
|
37
|
+
notSerializable(`${location}.${key}`, 'contains an accessor');
|
|
38
|
+
assertPlainData(descriptor.value, `${location}.${key}`, active);
|
|
39
|
+
}
|
|
40
|
+
active.delete(value);
|
|
41
|
+
}
|
|
42
|
+
function requireNonEmpty(value, location) {
|
|
43
|
+
if (value.length === 0)
|
|
44
|
+
throw new TypeError(`AMAMO_CONFIG_INVALID: ${location} must not be empty`);
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
function normalizeCollection(root, name, config) {
|
|
48
|
+
const extensions = config.extensions ?? ['.mdx'];
|
|
49
|
+
if (extensions.length === 0 || extensions.some((extension) => !extension.startsWith('.'))) {
|
|
50
|
+
throw new TypeError(`AMAMO_CONFIG_INVALID: collections.${name}.extensions must contain dotted extensions`);
|
|
51
|
+
}
|
|
52
|
+
if (config.locales && !config.locales.names.includes(config.locales.default)) {
|
|
53
|
+
throw new TypeError(`AMAMO_CONFIG_INVALID: collections.${name}.locales.default must be listed in names`);
|
|
54
|
+
}
|
|
55
|
+
const directory = path.resolve(root, requireNonEmpty(config.directory, `collections.${name}.directory`));
|
|
56
|
+
return {
|
|
57
|
+
directory: existsSync(directory) ? realpathSync.native(directory) : directory,
|
|
58
|
+
extensions: [...extensions],
|
|
59
|
+
locales: config.locales
|
|
60
|
+
? { default: config.locales.default, names: [...config.locales.names] }
|
|
61
|
+
: undefined,
|
|
62
|
+
schema: config.schema,
|
|
63
|
+
sensitive: [...(config.sensitive ?? [])],
|
|
64
|
+
slug: { indexNames: [...(config.slug?.indexNames ?? ['index', 'page'])] },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function defineConfig(config) {
|
|
68
|
+
return config;
|
|
69
|
+
}
|
|
70
|
+
export function normalizeConfig(config) {
|
|
71
|
+
assertPlainData(config, 'config', new WeakSet());
|
|
72
|
+
if (!config.collections || Object.keys(config.collections).length === 0) {
|
|
73
|
+
throw new TypeError('AMAMO_CONFIG_INVALID: collections must not be empty');
|
|
74
|
+
}
|
|
75
|
+
const resolvedRoot = path.resolve(config.root ?? process.cwd());
|
|
76
|
+
const root = existsSync(resolvedRoot) ? realpathSync.native(resolvedRoot) : resolvedRoot;
|
|
77
|
+
const generatedDirectory = path.resolve(root, config.generatedDirectory ?? '.amamo-mdx');
|
|
78
|
+
const collectionNames = Object.keys(config.collections);
|
|
79
|
+
const collections = Object.fromEntries(Object.entries(config.collections).map(([name, collection]) => [
|
|
80
|
+
requireNonEmpty(name, 'collection name'),
|
|
81
|
+
normalizeCollection(root, name, collection),
|
|
82
|
+
]));
|
|
83
|
+
const manifests = Object.fromEntries(Object.entries(config.manifests ?? {}).map(([name, manifest]) => [
|
|
84
|
+
requireNonEmpty(name, 'manifest name'),
|
|
85
|
+
{
|
|
86
|
+
...manifest,
|
|
87
|
+
collections: [...(manifest.collections ?? collectionNames)],
|
|
88
|
+
output: path.resolve(root, manifest.output),
|
|
89
|
+
},
|
|
90
|
+
]));
|
|
91
|
+
const highlight = config.highlight === false ? undefined : config.highlight;
|
|
92
|
+
const media = config.media === false ? undefined : config.media;
|
|
93
|
+
return {
|
|
94
|
+
cache: {
|
|
95
|
+
directory: path.resolve(root, config.cache === false
|
|
96
|
+
? '.amamo-mdx/cache'
|
|
97
|
+
: (config.cache?.directory ?? '.amamo-mdx/cache')),
|
|
98
|
+
enabled: config.cache !== false,
|
|
99
|
+
},
|
|
100
|
+
collections,
|
|
101
|
+
derived: {
|
|
102
|
+
lastModified: config.derived?.lastModified ?? false,
|
|
103
|
+
readingTime: config.derived?.readingTime ?? false,
|
|
104
|
+
},
|
|
105
|
+
generatedDirectory,
|
|
106
|
+
highlight: {
|
|
107
|
+
colorReplacements: { ...highlight?.colorReplacements },
|
|
108
|
+
enabled: config.highlight !== false,
|
|
109
|
+
engine: highlight?.engine ?? 'oniguruma',
|
|
110
|
+
languages: highlight?.languages === 'auto' || highlight?.languages === undefined
|
|
111
|
+
? 'auto'
|
|
112
|
+
: [...highlight.languages],
|
|
113
|
+
provider: 'shiki',
|
|
114
|
+
themes: highlight?.themes ?? { light: 'vitesse-light', dark: 'vitesse-dark' },
|
|
115
|
+
unknownLanguage: highlight?.unknownLanguage ?? 'error',
|
|
116
|
+
},
|
|
117
|
+
manifests,
|
|
118
|
+
mdx: {
|
|
119
|
+
gfm: config.mdx?.gfm ?? true,
|
|
120
|
+
hardBreaks: config.mdx?.hardBreaks ?? false,
|
|
121
|
+
jsxImportSource: config.mdx?.jsxImportSource ?? 'react',
|
|
122
|
+
providerImportSource: config.mdx?.providerImportSource ?? '',
|
|
123
|
+
},
|
|
124
|
+
media: {
|
|
125
|
+
attributes: Object.fromEntries(Object.entries(media?.attributes ?? DEFAULT_MEDIA_ATTRIBUTES).map(([tag, attributes]) => [
|
|
126
|
+
tag,
|
|
127
|
+
[...attributes],
|
|
128
|
+
])),
|
|
129
|
+
enabled: config.media !== false,
|
|
130
|
+
missing: media?.missing ?? 'error',
|
|
131
|
+
},
|
|
132
|
+
root,
|
|
133
|
+
};
|
|
134
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { IAmamoMdxConfig, ICacheConfig, ICollectionConfig, IDerivedConfig, IHighlightConfig, ILocaleConfig, IManifestConfig, IMdxConfig, IMediaConfig, INormalizedConfig, JsonValue, ManifestField, } from './config.js';
|
|
2
|
+
export { defineConfig, normalizeConfig } from './config.js';
|
|
3
|
+
export type { IBuildResult, ICompiler, ITransformResult } from './compiler.js';
|
|
4
|
+
export { createCompiler } from './compiler.js';
|
|
5
|
+
export type { IDiagnostic } from './native.js';
|
package/dist/index.js
ADDED
package/dist/native.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { INormalizedConfig, JsonValue } from './config.js';
|
|
2
|
+
export interface ISourcePoint {
|
|
3
|
+
column: number;
|
|
4
|
+
line: number;
|
|
5
|
+
offset: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ISourceRange {
|
|
8
|
+
end: ISourcePoint;
|
|
9
|
+
start: ISourcePoint;
|
|
10
|
+
}
|
|
11
|
+
export interface IDiagnostic {
|
|
12
|
+
code: string;
|
|
13
|
+
file?: string;
|
|
14
|
+
hint?: string;
|
|
15
|
+
message: string;
|
|
16
|
+
range?: ISourceRange;
|
|
17
|
+
severity: 'error' | 'warning';
|
|
18
|
+
}
|
|
19
|
+
export interface INativeDocumentInput {
|
|
20
|
+
collection: string;
|
|
21
|
+
file: string;
|
|
22
|
+
key: string;
|
|
23
|
+
locale?: string;
|
|
24
|
+
modifiedAt?: string;
|
|
25
|
+
slug?: string;
|
|
26
|
+
source: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ICodeBlock {
|
|
29
|
+
blockId: number;
|
|
30
|
+
code: string;
|
|
31
|
+
documentId: string;
|
|
32
|
+
lang: string | null;
|
|
33
|
+
meta: string | null;
|
|
34
|
+
}
|
|
35
|
+
export interface IHighlightedCodeBlock {
|
|
36
|
+
blockId: number;
|
|
37
|
+
documentId: string;
|
|
38
|
+
hast: JsonValue;
|
|
39
|
+
}
|
|
40
|
+
export interface IDocumentRecord {
|
|
41
|
+
cacheKey: string;
|
|
42
|
+
cached: boolean;
|
|
43
|
+
collection: string;
|
|
44
|
+
dependencies: string[];
|
|
45
|
+
derived: Record<string, JsonValue>;
|
|
46
|
+
diagnostics: IDiagnostic[];
|
|
47
|
+
file: string;
|
|
48
|
+
frontmatter: Record<string, JsonValue>;
|
|
49
|
+
hash: string;
|
|
50
|
+
key: string;
|
|
51
|
+
locale?: string;
|
|
52
|
+
module: string;
|
|
53
|
+
projections: Record<string, JsonValue>;
|
|
54
|
+
slug?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface IRenderedManifest {
|
|
57
|
+
contents: string;
|
|
58
|
+
path: string;
|
|
59
|
+
}
|
|
60
|
+
export interface IPreparedNativeBatch {
|
|
61
|
+
codeBlocks: ICodeBlock[];
|
|
62
|
+
finish(highlights: IHighlightedCodeBlock[]): IDocumentRecord[];
|
|
63
|
+
}
|
|
64
|
+
export declare class AmamoMdxError extends Error {
|
|
65
|
+
readonly diagnostics: IDiagnostic[];
|
|
66
|
+
constructor(diagnostics: IDiagnostic[]);
|
|
67
|
+
}
|
|
68
|
+
export declare function configurationFingerprint(config: INormalizedConfig): string;
|
|
69
|
+
export declare function prepareNativeBatch(config: INormalizedConfig, inputs: INativeDocumentInput[]): IPreparedNativeBatch;
|
|
70
|
+
export declare function pruneNativeCache(cacheDirectory: string, keepKeys: string[]): number;
|
|
71
|
+
export declare function renderNativeManifests(config: INormalizedConfig, records: IDocumentRecord[]): IRenderedManifest[];
|
package/dist/native.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
export class AmamoMdxError extends Error {
|
|
4
|
+
diagnostics;
|
|
5
|
+
constructor(diagnostics) {
|
|
6
|
+
super(diagnostics.map((diagnostic) => diagnostic.message).join('\n'));
|
|
7
|
+
this.name = 'AmamoMdxError';
|
|
8
|
+
this.diagnostics = diagnostics;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
12
|
+
const packageVersion = require('../package.json').version;
|
|
13
|
+
const shikiVersion = require('shiki/package.json').version;
|
|
14
|
+
function nativeConfigJson(config) {
|
|
15
|
+
return JSON.stringify({
|
|
16
|
+
...config,
|
|
17
|
+
_runtime: { packageVersion, shikiVersion },
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export function configurationFingerprint(config) {
|
|
21
|
+
return createHash('sha256').update(nativeConfigJson(config)).digest('hex');
|
|
22
|
+
}
|
|
23
|
+
function loadBinding() {
|
|
24
|
+
return require('../native.cjs');
|
|
25
|
+
}
|
|
26
|
+
function mapNativeError(error) {
|
|
27
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
28
|
+
const marker = 'AMAMO_MDX_DIAGNOSTICS:';
|
|
29
|
+
const index = message.indexOf(marker);
|
|
30
|
+
if (index === -1)
|
|
31
|
+
throw error;
|
|
32
|
+
throw new AmamoMdxError(JSON.parse(message.slice(index + marker.length)));
|
|
33
|
+
}
|
|
34
|
+
export function prepareNativeBatch(config, inputs) {
|
|
35
|
+
try {
|
|
36
|
+
const batch = loadBinding().prepareBatch(nativeConfigJson(config), JSON.stringify(inputs));
|
|
37
|
+
return {
|
|
38
|
+
codeBlocks: JSON.parse(batch.codeBlocksJson),
|
|
39
|
+
finish(highlights) {
|
|
40
|
+
try {
|
|
41
|
+
return JSON.parse(batch.finish(JSON.stringify(highlights)));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return mapNativeError(error);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
return mapNativeError(error);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function pruneNativeCache(cacheDirectory, keepKeys) {
|
|
54
|
+
try {
|
|
55
|
+
return loadBinding().pruneCache(cacheDirectory, JSON.stringify(keepKeys));
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return mapNativeError(error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function renderNativeManifests(config, records) {
|
|
62
|
+
try {
|
|
63
|
+
return JSON.parse(loadBinding().renderManifests(nativeConfigJson(config), JSON.stringify(records)));
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return mapNativeError(error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
const promises_1 = require("node:fs/promises");
|
|
6
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
7
|
+
function nextLoader(_source) {
|
|
8
|
+
return readCompiledModule(this);
|
|
9
|
+
}
|
|
10
|
+
async function readCompiledModule(context) {
|
|
11
|
+
const options = context.getOptions();
|
|
12
|
+
try {
|
|
13
|
+
const index = JSON.parse(await (0, promises_1.readFile)(options.indexFile, 'utf8'));
|
|
14
|
+
const resource = await (0, promises_1.realpath)(node_path_1.default.resolve(context.resourcePath));
|
|
15
|
+
const cacheKey = index.documents?.[resource]?.cacheKey;
|
|
16
|
+
if (index.configFingerprint !== options.configFingerprint ||
|
|
17
|
+
typeof index.cacheDirectory !== 'string' ||
|
|
18
|
+
typeof cacheKey !== 'string' ||
|
|
19
|
+
!/^[a-f0-9]{64}$/.test(cacheKey)) {
|
|
20
|
+
throw new Error('index entry does not match this build');
|
|
21
|
+
}
|
|
22
|
+
const cacheFile = node_path_1.default.join(index.cacheDirectory, cacheKey.slice(0, 2), `${cacheKey}.json`);
|
|
23
|
+
const record = JSON.parse(await (0, promises_1.readFile)(cacheFile, 'utf8'));
|
|
24
|
+
if (record.cacheKey !== cacheKey || typeof record.module !== 'string') {
|
|
25
|
+
throw new Error('cache record does not match its index entry');
|
|
26
|
+
}
|
|
27
|
+
return record.module;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new Error(`AMAMO_NEXT_CACHE_MISS: ${context.resourcePath}; rerun the coordinated amamo-mdx build`, { cause: error });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
module.exports = nextLoader;
|
package/dist/next.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { NextConfig } from 'next';
|
|
2
|
+
import type { IAmamoMdxConfig } from './config.js';
|
|
3
|
+
export interface IAmamoNextConfigContext {
|
|
4
|
+
defaultConfig: NextConfig;
|
|
5
|
+
}
|
|
6
|
+
export type AmamoNextConfigInput = NextConfig | Promise<NextConfig> | ((phase: string, context: IAmamoNextConfigContext) => NextConfig | Promise<NextConfig>);
|
|
7
|
+
export type AmamoNextConfig = (phase: string, context: IAmamoNextConfigContext) => Promise<NextConfig>;
|
|
8
|
+
export declare function withAmamoMdx(config: IAmamoMdxConfig): (nextConfig?: AmamoNextConfigInput) => AmamoNextConfig;
|
package/dist/next.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } from 'next/constants.js';
|
|
4
|
+
import { normalizeConfig } from './config.js';
|
|
5
|
+
import { createAdapterCompiler } from './compiler.js';
|
|
6
|
+
import { configurationFingerprint } from './native.js';
|
|
7
|
+
export function withAmamoMdx(config) {
|
|
8
|
+
const normalized = normalizeConfig(config);
|
|
9
|
+
const loader = fileURLToPath(new URL('./next-loader.cjs', import.meta.url));
|
|
10
|
+
const loaderOptions = {
|
|
11
|
+
configFingerprint: configurationFingerprint(normalized),
|
|
12
|
+
indexFile: path.join(normalized.generatedDirectory, 'index.json'),
|
|
13
|
+
};
|
|
14
|
+
let compilerPromise;
|
|
15
|
+
let buildPromise;
|
|
16
|
+
let watching = false;
|
|
17
|
+
function compiler() {
|
|
18
|
+
compilerPromise ??= createAdapterCompiler(config);
|
|
19
|
+
return compilerPromise;
|
|
20
|
+
}
|
|
21
|
+
async function prepare(phase) {
|
|
22
|
+
if (phase !== PHASE_DEVELOPMENT_SERVER && phase !== PHASE_PRODUCTION_BUILD)
|
|
23
|
+
return;
|
|
24
|
+
buildPromise ??= compiler().then((instance) => instance.build());
|
|
25
|
+
await buildPromise;
|
|
26
|
+
if (phase === PHASE_DEVELOPMENT_SERVER && !watching) {
|
|
27
|
+
const instance = await compiler();
|
|
28
|
+
instance.startWatch();
|
|
29
|
+
watching = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return function applyAmamoMdx(nextConfig = {}) {
|
|
33
|
+
return async (phase, context) => {
|
|
34
|
+
const resolved = typeof nextConfig === 'function' ? await nextConfig(phase, context) : await nextConfig;
|
|
35
|
+
await prepare(phase);
|
|
36
|
+
const existingWebpack = resolved.webpack;
|
|
37
|
+
return {
|
|
38
|
+
...resolved,
|
|
39
|
+
turbopack: {
|
|
40
|
+
...resolved.turbopack,
|
|
41
|
+
rules: {
|
|
42
|
+
...resolved.turbopack?.rules,
|
|
43
|
+
'*.mdx': {
|
|
44
|
+
as: '*.js',
|
|
45
|
+
loaders: [{ loader, options: loaderOptions }],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
webpack(webpackConfig, webpackContext) {
|
|
50
|
+
const configured = existingWebpack
|
|
51
|
+
? existingWebpack(webpackConfig, webpackContext)
|
|
52
|
+
: webpackConfig;
|
|
53
|
+
configured.module ??= {};
|
|
54
|
+
configured.module.rules ??= [];
|
|
55
|
+
configured.module.rules.push({
|
|
56
|
+
test: /\.mdx$/,
|
|
57
|
+
use: [{ loader, options: loaderOptions }],
|
|
58
|
+
});
|
|
59
|
+
return configured;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
}
|
package/dist/shiki.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { INormalizedHighlightConfig } from './config.js';
|
|
2
|
+
import type { ICodeBlock, IHighlightedCodeBlock } from './native.js';
|
|
3
|
+
export interface IShikiRenderer {
|
|
4
|
+
dispose(): void;
|
|
5
|
+
highlight(blocks: ICodeBlock[]): Promise<IHighlightedCodeBlock[]>;
|
|
6
|
+
}
|
|
7
|
+
export declare function createShikiRenderer(config: INormalizedHighlightConfig): Promise<IShikiRenderer>;
|
package/dist/shiki.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { createHighlighterCore } from 'shiki/core';
|
|
2
|
+
import { createJavaScriptRegexEngine } from 'shiki/engine/javascript';
|
|
3
|
+
import { createOnigurumaEngine } from 'shiki/engine/oniguruma';
|
|
4
|
+
import { bundledLanguages, bundledLanguagesAlias } from 'shiki/langs';
|
|
5
|
+
import { bundledThemes } from 'shiki/themes';
|
|
6
|
+
function themeLoader(name) {
|
|
7
|
+
if (!Object.hasOwn(bundledThemes, name)) {
|
|
8
|
+
throw new Error(`AMAMO_SHIKI_UNKNOWN_THEME: Unknown bundled Shiki theme \`${name}\``);
|
|
9
|
+
}
|
|
10
|
+
return bundledThemes[name];
|
|
11
|
+
}
|
|
12
|
+
function languageLoader(name) {
|
|
13
|
+
if (Object.hasOwn(bundledLanguages, name)) {
|
|
14
|
+
return bundledLanguages[name];
|
|
15
|
+
}
|
|
16
|
+
if (Object.hasOwn(bundledLanguagesAlias, name)) {
|
|
17
|
+
return bundledLanguagesAlias[name];
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
export async function createShikiRenderer(config) {
|
|
22
|
+
const engine = config.engine === 'javascript'
|
|
23
|
+
? createJavaScriptRegexEngine()
|
|
24
|
+
: createOnigurumaEngine(import('shiki/wasm'));
|
|
25
|
+
const highlighter = await createHighlighterCore({
|
|
26
|
+
engine,
|
|
27
|
+
langs: [],
|
|
28
|
+
themes: [themeLoader(config.themes.light), themeLoader(config.themes.dark)],
|
|
29
|
+
});
|
|
30
|
+
const loading = new Map();
|
|
31
|
+
let disposed = false;
|
|
32
|
+
async function loadLanguage(requested) {
|
|
33
|
+
if (!requested || requested === 'text' || requested === 'plain' || requested === 'plaintext') {
|
|
34
|
+
return 'text';
|
|
35
|
+
}
|
|
36
|
+
const existing = loading.get(requested);
|
|
37
|
+
if (existing)
|
|
38
|
+
return existing;
|
|
39
|
+
const loader = languageLoader(requested);
|
|
40
|
+
if (!loader) {
|
|
41
|
+
if (config.unknownLanguage === 'plain')
|
|
42
|
+
return 'text';
|
|
43
|
+
throw new Error(`AMAMO_SHIKI_UNKNOWN_LANGUAGE: Unknown bundled Shiki language \`${requested}\``);
|
|
44
|
+
}
|
|
45
|
+
const promise = highlighter.loadLanguage(loader).then(() => requested);
|
|
46
|
+
loading.set(requested, promise);
|
|
47
|
+
return promise;
|
|
48
|
+
}
|
|
49
|
+
if (config.languages !== 'auto') {
|
|
50
|
+
await Promise.all(config.languages.map((language) => loadLanguage(language)));
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
dispose() {
|
|
54
|
+
if (disposed)
|
|
55
|
+
return;
|
|
56
|
+
disposed = true;
|
|
57
|
+
highlighter.dispose();
|
|
58
|
+
},
|
|
59
|
+
async highlight(blocks) {
|
|
60
|
+
if (disposed)
|
|
61
|
+
throw new Error('AMAMO_SHIKI_DISPOSED: Shiki renderer is disposed');
|
|
62
|
+
const languages = await Promise.all(blocks.map((block) => loadLanguage(block.lang)));
|
|
63
|
+
return blocks.map((block, index) => {
|
|
64
|
+
const hast = highlighter.codeToHast(block.code, {
|
|
65
|
+
colorReplacements: config.colorReplacements,
|
|
66
|
+
defaultColor: false,
|
|
67
|
+
lang: languages[index] ?? 'text',
|
|
68
|
+
meta: block.meta ? { __raw: block.meta } : undefined,
|
|
69
|
+
themes: {
|
|
70
|
+
dark: config.themes.dark,
|
|
71
|
+
light: config.themes.light,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
blockId: block.blockId,
|
|
76
|
+
documentId: block.documentId,
|
|
77
|
+
hast: JSON.parse(JSON.stringify(hast)),
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
package/dist/vite.d.ts
ADDED