211 lines
6.3 KiB
JavaScript
211 lines
6.3 KiB
JavaScript
import { copyFileSync, readFileSync, writeFileSync } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
|
|
const packageDir = resolve(import.meta.dirname, '../../../packages/decodal-wasm');
|
|
|
|
copyFileSync(resolve(packageDir, '../../LICENSE-MIT'), resolve(packageDir, 'LICENSE-MIT'));
|
|
copyFileSync(resolve(packageDir, '../../LICENSE-APACHE'), resolve(packageDir, 'LICENSE-APACHE'));
|
|
|
|
const declarationPath = resolve(packageDir, 'decodal_wasm.d.ts');
|
|
let declarations = readFileSync(declarationPath, 'utf8');
|
|
const hostTypes = `
|
|
/** A concrete JavaScript value or Decodal schema descriptor supplied by the host. */
|
|
export type DecodalHostValue =
|
|
| string
|
|
| number
|
|
| boolean
|
|
| DecodalHostValue[]
|
|
| { [field: string]: DecodalHostValue }
|
|
| DecodalPrimitiveDescriptor
|
|
| DecodalArrayDescriptor
|
|
| DecodalMapDescriptor
|
|
| DecodalAbstractDescriptor;
|
|
|
|
export type DecodalPrimitiveType = 'String' | 'Int' | 'Float' | 'Bool';
|
|
|
|
export type DecodalConstraint =
|
|
| { kind: 'type'; value: DecodalPrimitiveType }
|
|
| { kind: 'compare'; op: '>' | '>=' | '<' | '<='; value: string | number | boolean }
|
|
| { kind: 'regex'; value: string }
|
|
| { kind: 'predicate'; value: string };
|
|
|
|
export interface DecodalPrimitiveDescriptor {
|
|
$decodal: DecodalPrimitiveType;
|
|
constraints?: DecodalConstraint[];
|
|
default?: DecodalHostValue;
|
|
}
|
|
|
|
export interface DecodalArrayDescriptor {
|
|
$decodal: 'Array';
|
|
item: DecodalHostValue;
|
|
constraints?: DecodalConstraint[];
|
|
default?: DecodalHostValue;
|
|
}
|
|
|
|
export interface DecodalMapDescriptor {
|
|
$decodal: 'Map';
|
|
value: DecodalHostValue;
|
|
constraints?: DecodalConstraint[];
|
|
default?: DecodalHostValue;
|
|
}
|
|
|
|
export interface DecodalAbstractDescriptor {
|
|
$decodal: 'Abstract';
|
|
constraints?: DecodalConstraint[];
|
|
default?: DecodalHostValue;
|
|
}
|
|
|
|
export type DecodalLoadedImport =
|
|
| { kind: 'source'; key: string; name?: string; source: string }
|
|
| { kind: 'value'; key: string; value: DecodalHostValue };
|
|
|
|
export type DecodalImportCandidate =
|
|
| string
|
|
| { specifier: string; detail?: string };
|
|
|
|
/** Host-owned environment shared by evaluation and language tooling. */
|
|
export interface DecodalEnvironment {
|
|
globals?: Record<string, DecodalHostValue>;
|
|
/** Synchronous import callback. Preload or cache asynchronous resources first. */
|
|
loadImport?: (currentKey: string | null, specifier: string) => DecodalLoadedImport;
|
|
/** Synchronous import completion callback. */
|
|
completeImport?: (currentKey: string | null, prefix: string) => DecodalImportCandidate[];
|
|
}
|
|
`;
|
|
if (!declarations.includes('export interface DecodalEnvironment')) {
|
|
declarations = declarations.replace('/* eslint-disable */\n', `/* eslint-disable */\n${hostTypes}`);
|
|
}
|
|
declarations = declarations.replace(
|
|
'constructor(options: any);',
|
|
'constructor(options?: DecodalEnvironment);',
|
|
);
|
|
writeFileSync(declarationPath, declarations);
|
|
|
|
writeFileSync(
|
|
resolve(packageDir, '.gitignore'),
|
|
'# wasm-pack output is committed for the browser runtime package.\n',
|
|
);
|
|
|
|
const packageJsonPath = resolve(packageDir, 'package.json');
|
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
packageJson.version = '0.2.0';
|
|
packageJson.files = [
|
|
'README.md',
|
|
'LICENSE-MIT',
|
|
'LICENSE-APACHE',
|
|
'decodal_wasm_bg.wasm',
|
|
'decodal_wasm.js',
|
|
'decodal_wasm.d.ts',
|
|
];
|
|
packageJson.exports = {
|
|
'.': {
|
|
types: './decodal_wasm.d.ts',
|
|
import: './decodal_wasm.js',
|
|
},
|
|
'./decodal_wasm_bg.wasm': './decodal_wasm_bg.wasm',
|
|
'./package.json': './package.json',
|
|
};
|
|
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|
|
|
|
writeFileSync(
|
|
resolve(packageDir, 'README.md'),
|
|
`# decodal-wasm
|
|
|
|
WebAssembly runtime package for Decodal.
|
|
|
|
This package exposes the Decodal evaluator and shared language service to browsers and other JavaScript runtimes that can load WebAssembly modules.
|
|
It is generated from the Rust crate in \`crates/decodal-wasm\` with \`wasm-pack\` and is used by the official playground.
|
|
|
|
Use \`decodal-codemirror\` separately when you need CodeMirror 6 language support.
|
|
|
|
## Install
|
|
|
|
\`\`\`sh
|
|
npm install decodal-wasm
|
|
\`\`\`
|
|
|
|
JSR:
|
|
|
|
\`\`\`sh
|
|
deno add jsr:@hare/decodal-wasm
|
|
\`\`\`
|
|
|
|
## Usage
|
|
|
|
\`\`\`js
|
|
import init, { DecodalLanguageService } from 'decodal-wasm';
|
|
|
|
await init();
|
|
|
|
const files = {
|
|
'main.dcdl': 'let schema = import "./schema.dcdl"; in schema.Server',
|
|
'schema.dcdl': 'Server = { port = 8080; } as App.Server;',
|
|
};
|
|
|
|
const service = new DecodalLanguageService({
|
|
globals: {
|
|
App: {
|
|
Server: {
|
|
port: { $decodal: 'Int' },
|
|
},
|
|
},
|
|
},
|
|
loadImport(_currentKey, specifier) {
|
|
const key = specifier.startsWith('./') ? specifier.slice(2) : specifier;
|
|
return { kind: 'source', key, name: key, source: files[key] };
|
|
},
|
|
completeImport() {
|
|
return ['./schema.dcdl'];
|
|
},
|
|
});
|
|
|
|
const result = service.evaluate('main.dcdl', 'main.dcdl', files['main.dcdl']);
|
|
|
|
console.log(JSON.parse(result));
|
|
|
|
const completion = service.complete(
|
|
'main.dcdl',
|
|
'App.Server.po',
|
|
'App.Server.po'.length,
|
|
false,
|
|
);
|
|
|
|
console.log(JSON.parse(completion));
|
|
\`\`\`
|
|
|
|
\`globals\`, \`loadImport\`, and \`completeImport\` are host-owned. The package does not assume a filesystem or virtual project model. Import callbacks are synchronous; preload or cache remote content before evaluation.
|
|
|
|
Plain strings, numbers, booleans, arrays, and objects are concrete host values. Use \`{ $decodal: 'String' | 'Int' | 'Float' | 'Bool' }\` for primitive schemas, \`{ $decodal: 'Array', item: value }\` for array schemas, and \`{ $decodal: 'Map', value: value }\` for associative-array schemas. Descriptors also accept \`constraints\` and \`default\`.
|
|
|
|
Methods return JSON strings so callers can handle diagnostics and successful results without depending on Rust data structures.
|
|
`,
|
|
);
|
|
|
|
writeFileSync(
|
|
resolve(packageDir, 'jsr.json'),
|
|
JSON.stringify(
|
|
{
|
|
name: '@hare/decodal-wasm',
|
|
version: '0.2.0',
|
|
// JSR's publisher currently accepts a single recognized identifier.
|
|
// npm package metadata remains dual-licensed and both files are included.
|
|
license: 'MIT',
|
|
exports: './mod.ts',
|
|
publish: {
|
|
include: [
|
|
'README.md',
|
|
'LICENSE-MIT',
|
|
'LICENSE-APACHE',
|
|
'mod.ts',
|
|
'decodal_wasm.js',
|
|
'decodal_wasm.d.ts',
|
|
'decodal_wasm_bg.wasm',
|
|
'package.json',
|
|
],
|
|
},
|
|
},
|
|
null,
|
|
2,
|
|
) + '\n',
|
|
);
|