Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

elm-spa

Package Overview
Dependencies
Maintainers
1
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

elm-spa - npm Package Compare versions

Comparing version 6.0.0--beta to 6.0.0

.elm-spa/defaults/Auth.elm

4

dist/package.json
{
"name": "elm-spa",
"version": "6.0.0--beta",
"version": "6.0.0",
"description": "single page apps made easy",

@@ -43,4 +43,4 @@ "bin": "dist/src/index.js",

"chokidar": "3.4.2",
"elm": "0.19.1-3",
"mime": "2.4.6",
"node-elm-compiler": "5.0.5",
"terser": "5.3.8",

@@ -47,0 +47,0 @@ "websocket": "1.0.32"

@@ -15,6 +15,10 @@ "use strict";

add: add_1.default.run,
build: build_1.default.run,
build: build_1.default.build,
server: server_1.default.run,
gen: build_1.default.gen,
watch: watch_1.default.run,
server: server_1.default.run,
help: help_1.default.run
help: help_1.default.run,
// Aliases for Elm folks
init: init_1.default.run,
make: build_1.default.build,
};

@@ -30,15 +30,56 @@ "use strict";

const add_1 = __importDefault(require("../templates/add"));
const terminal_1 = require("../terminal");
const _common_1 = require("./_common");
const bold = (str) => '\x1b[1m' + str + '\x1b[0m';
const cyan = (str) => '\x1b[36m' + str + '\x1b[0m';
const green = (str) => '\x1b[32m' + str + '\x1b[0m';
const yellow = (str) => '\x1b[33m' + str + '\x1b[0m';
const pink = (str) => '\x1b[35m' + str + '\x1b[0m';
// Scaffold a new elm-spa page
exports.default = {
run: async () => {
let url = process.argv[3];
if (!url) {
return Promise.reject(`${terminal_1.bold}elm-spa add${terminal_1.reset} requires a ${terminal_1.bold}url${terminal_1.reset} parameter!`);
let [url, template] = process.argv.slice(3);
if (!url || url === '--help') {
return Promise.reject(example);
}
const page = utils_1.urlArgumentToPages(url);
const filepath = path_1.default.join(config_1.default.folders.pages.src, ...page) + '.elm';
await File.create(filepath, add_1.default(page));
return ` ${terminal_1.bold}New page created at:${terminal_1.reset}\n ${filepath}`;
const outputFilepath = path_1.default.join(config_1.default.folders.pages.src, ...page) + '.elm';
let contents = add_1.default(page);
if (template) {
const availableTemplates = await _common_1.createMissingAddTemplates();
const templateSrc = path_1.default.join(config_1.default.folders.templates.user, template + '.elm');
contents = await File.read(templateSrc).catch(_ => Promise.reject(template404(url, template, availableTemplates)));
contents = contents.split('{{module}}').join(page.join('.'));
}
await File.create(outputFilepath, contents);
return ` ${bold('New page created at:')}\n ${outputFilepath}\n`;
}
};
const example = ' ' + `
${bold(`elm-spa add`)} <url> [template]
Examples:
${bold(`elm-spa ${cyan(`add`)}`)} ${yellow('/')} . . . . . . . . adds a homepage
${bold(`elm-spa ${cyan(`add`)}`)} ${yellow('/about-us')} . . . . adds a static route
${bold(`elm-spa ${cyan(`add`)}`)} ${yellow('/people/:id')} . . . adds a dynamic route
Examples with templates:
${bold(`elm-spa ${cyan(`add`)}`)} ${yellow('/')} ${pink('static')}
${bold(`elm-spa ${cyan(`add`)}`)} ${yellow('/about-us')} ${pink('sandbox')}
${bold(`elm-spa ${cyan(`add`)}`)} ${yellow('/people/:id')} ${pink('element')}
Visit ${green(`https://elm-spa.dev/guide/cli`)} for more details!
`.trim();
const template404 = (url, template, suggestions) => {
const suggest = `
Here are the available templates:
${suggestions.map(temp => `${yellow(`elm-spa add`)} ${yellow(url)} ${bold(pink(temp))}`).join('\n ')}
`;
return ' ' + `
${bold(`elm-spa`)} couldn't find a ${bold(pink(template))} template
in the ${cyan('.elm-spa/templates')} folder.
${suggestions.length ? suggest : ''}
Visit ${green(`https://elm-spa.dev/guide/cli`)} for more details!
`.trim();
};

@@ -30,13 +30,22 @@ "use strict";

const File = __importStar(require("../file"));
const readline_1 = require("readline");
const routes_1 = __importDefault(require("../templates/routes"));
const pages_1 = __importDefault(require("../templates/pages"));
const page_1 = __importDefault(require("../templates/page"));
const request_1 = __importDefault(require("../templates/request"));
const model_1 = __importDefault(require("../templates/model"));
const msg_1 = __importDefault(require("../templates/msg"));
const child_process_1 = __importDefault(require("child_process"));
const params_1 = __importDefault(require("../templates/params"));
const Process = __importStar(require("../process"));
const terser_1 = __importDefault(require("terser"));
const terminal_1 = require("../terminal");
const utils_1 = require("../templates/utils");
exports.build = (env) => () => createMissingDefaultFiles()
const _common_1 = require("./_common");
const elm = require('node-elm-compiler');
exports.build = ({ env, runElmMake }) => () => Promise.all([
createMissingDefaultFiles(),
_common_1.createMissingAddTemplates()
])
.then(createGeneratedFiles)
.then(compileMainElm(env));
.then(runElmMake ? compileMainElm(env) : _ => ` ${terminal_1.check} ${terminal_1.bold}elm-spa${terminal_1.reset} generated new files.`);
const createMissingDefaultFiles = async () => {

@@ -66,24 +75,48 @@ const toAction = async (filepath) => {

};
const scanForStaticPages = async (entries) => {
const getFilepathSegments = async (entries) => {
const contents = await Promise.all(entries.map(e => File.read(e.filepath)));
return contents
.map((content, i) => utils_1.isStaticPage(content) ? i : undefined)
.filter(a => typeof a === 'number')
.map((i) => entries[i].segments);
return Promise.all(entries.map(async (entry, i) => {
const c = contents[i];
const kind = await (utils_1.isStandardPage(c) ? Promise.resolve('page')
: utils_1.isStaticPage(c) ? Promise.resolve('static-page')
: utils_1.isStaticView(c) ? Promise.resolve('view')
: Promise.reject(invalidExportsMessage(entry)));
return { kind, entry };
}));
};
const invalidExportsMessage = (entry) => {
const moduleName = `${terminal_1.bold}Pages.${entry.segments.join('.')}${terminal_1.reset}`;
const cyan = (str) => `${terminal_1.colors.cyan}${str}${terminal_1.reset}`;
return [
`${terminal_1.colors.RED}!${terminal_1.reset} Ran into a problem at ${terminal_1.bold}${terminal_1.colors.yellow}src/Pages/${entry.segments.join('/')}.elm${terminal_1.reset}`,
``,
`${terminal_1.bold}elm-spa${terminal_1.reset} expected one of these module definitions:`,
``,
` ${terminal_1.dot} module ${moduleName} exposing (${cyan('view')})`,
` ${terminal_1.dot} module ${moduleName} exposing (${cyan('page')})`,
` ${terminal_1.dot} module ${moduleName} exposing (${cyan('Model')}, ${cyan('Msg')}, ${cyan('page')})`,
``,
`Visit ${terminal_1.colors.green}https://elm-spa.dev/guide/pages${terminal_1.reset} for more details!`
].join('\n');
};
const createGeneratedFiles = async () => {
const entries = await getAllPageEntries();
const filepaths = entries.map(e => e.segments);
const staticPages = await scanForStaticPages(entries);
const isStatic = (path) => staticPages.map(p => p.join('.')).includes(path.join('.'));
const paramFiles = filepaths.map(filepath => ({
const segments = entries.map(e => e.segments);
const filepathSegments = await getFilepathSegments(entries);
const kindForPage = (p) => filepathSegments
.filter(item => item.entry.segments.join('.') == p.join('.'))
.map(fps => fps.kind)[0] || 'page';
const paramFiles = segments.map(filepath => ({
filepath: ['Gen', 'Params', ...filepath],
contents: params_1.default(filepath, { isStatic })
contents: params_1.default(filepath, utils_1.options(kindForPage))
}));
const filesToCreate = [
...paramFiles,
{ filepath: ['Gen', 'Route'], contents: routes_1.default(filepaths, { isStatic }) },
{ filepath: ['Gen', 'Pages'], contents: pages_1.default(filepaths, { isStatic }) },
{ filepath: ['Gen', 'Model'], contents: model_1.default(filepaths, { isStatic }) },
{ filepath: ['Gen', 'Msg'], contents: msg_1.default(filepaths, { isStatic }) }
{ filepath: ['Page'], contents: page_1.default() },
{ filepath: ['Request'], contents: request_1.default() },
{ filepath: ['Gen', 'Route'], contents: routes_1.default(segments, utils_1.options(kindForPage)) },
{ filepath: ['Gen', 'Route'], contents: routes_1.default(segments, utils_1.options(kindForPage)) },
{ filepath: ['Gen', 'Pages'], contents: pages_1.default(segments, utils_1.options(kindForPage)) },
{ filepath: ['Gen', 'Model'], contents: model_1.default(segments, utils_1.options(kindForPage)) },
{ filepath: ['Gen', 'Msg'], contents: msg_1.default(segments, utils_1.options(kindForPage)) }
];

@@ -105,19 +138,40 @@ return Promise.all(filesToCreate.map(({ filepath, contents }) => File.create(path_1.default.join(config_1.default.folders.generated, ...filepath) + '.elm', contents)));

};
const output = path_1.default.join(config_1.default.folders.dist, 'elm.js');
const outputFilepath = path_1.default.join(config_1.default.folders.dist, 'elm.js');
const compileMainElm = (env) => async () => {
await ensureElmIsInstalled(env);
const start = Date.now();
const elmMake = async () => {
const flags = env === 'development' ? '--debug' : '--optimize';
const inDevelopment = env === 'development';
const inProduction = env === 'production';
const isSrcMainElmDefined = await File.exists(path_1.default.join(config_1.default.folders.src, 'Main.elm'));
const input = isSrcMainElmDefined
const inputFilepath = isSrcMainElmDefined
? path_1.default.join(config_1.default.folders.src, 'Main.elm')
: path_1.default.join(config_1.default.folders.defaults.dest, 'Main.elm');
if (await File.exists(config_1.default.folders.dist) === false) {
await File.mkdir(config_1.default.folders.dist);
}
return Process.run(`${config_1.default.binaries.elm} make ${input} --output=${output} --report=json ${flags}`)
.catch(colorElmError);
return elm.compileToString(inputFilepath, {
output: outputFilepath,
report: 'json',
debug: inDevelopment,
optimize: inProduction,
})
.catch((error) => {
try {
return colorElmError(JSON.parse(error.message.split('\n')[1]));
}
catch (_a) {
const { RED, green } = terminal_1.colors;
return Promise.reject([
`${RED}!${terminal_1.reset} elm-spa failed to understand an error`,
`Please report the output below to ${green}https://github.com/ryannhg/elm-spa/issues${terminal_1.reset}`,
`-----`,
error,
`-----`,
`${RED}!${terminal_1.reset} elm-spa failed to understand an error`,
`Please send the output above to ${green}https://github.com/ryannhg/elm-spa/issues${terminal_1.reset}`,
``
].join('\n\n'));
}
});
};
const colorElmError = (err) => {
const errors = JSON.parse(err).errors || [];
const colorElmError = (output) => {
const { errors } = output;
const strIf = (str) => (cond) => cond ? str : '';

@@ -140,16 +194,65 @@ const boldIf = strIf(terminal_1.bold);

};
return errors.length
? Promise.reject(errors.map(errorToString).join('\n\n\n'))
: err;
return Promise.reject(errors.map(err => errorToString(err)).join('\n\n\n'));
};
const success = () => `${terminal_1.check} Build successful! ${terminal_1.dim}(${Date.now() - start}ms)${terminal_1.reset}`;
const minify = () => Process.run(`${config_1.default.binaries.terser} ${output} --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | ${config_1.default.binaries.terser} --mangle --output=${output}`);
const minify = (rawCode) => terser_1.default.minify(rawCode, { compress: { pure_funcs: `F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9`.split(','), pure_getters: true, keep_fargs: false, unsafe_comps: true, unsafe: true } })
.then(intermediate => terser_1.default.minify(intermediate.code || '', { mangle: true }))
.then(minified => File.create(outputFilepath, minified.code || ''));
return (env === 'development')
? elmMake()
.then(_ => success()).catch(error => error)
: elmMake().then(minify)
.then(rawJsCode => File.create(outputFilepath, rawJsCode))
.then(_ => success())
.catch(error => error)
: elmMake()
.then(minify)
.then(_ => [success() + '\n']);
};
const ensureElmIsInstalled = async (environment) => {
await new Promise((resolve, reject) => {
child_process_1.default.exec('elm', (err) => {
if (err) {
if (environment === 'production') {
attemptToInstallViaNpm(resolve, reject);
}
else {
offerToInstallForDeveloper(resolve, reject);
}
}
else {
resolve(undefined);
}
});
});
};
const attemptToInstallViaNpm = (resolve, reject) => {
process.stdout.write(`\n ${terminal_1.bold}Awesome!${terminal_1.reset} Installing Elm via NPM... `);
child_process_1.default.exec(`npm install --global elm@latest-0.19.1`, (err) => {
if (err) {
console.info(terminal_1.error);
reject(` The automatic install didn't work...\n Please visit ${terminal_1.colors.green}https://guide.elm-lang.org/install/elm${terminal_1.reset} to install Elm.\n`);
}
else {
console.info(terminal_1.check);
console.info(` Elm is now installed!`);
resolve(undefined);
}
});
};
const offerToInstallForDeveloper = (resolve, reject) => {
const rl = readline_1.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question(`\n${terminal_1.warn} Elm hasn't been installed yet.\n\n May I ${terminal_1.colors.cyan}install${terminal_1.reset} it for you? ${terminal_1.dim}[y/n]${terminal_1.reset} `, answer => {
if (answer.toLowerCase() === 'n') {
reject(` ${terminal_1.bold}No changes made!${terminal_1.reset}\n Please visit ${terminal_1.colors.green}https://guide.elm-lang.org/install/elm${terminal_1.reset} to install Elm.`);
}
else {
attemptToInstallViaNpm(resolve, reject);
}
});
};
exports.default = {
run: exports.build('production')
build: exports.build({ env: 'production', runElmMake: true }),
gen: exports.build({ env: 'production', runElmMake: false })
};

@@ -21,6 +21,9 @@ "use strict";

${bold(`elm-spa ${cyan(`build`)}`)} . . . . . . one-time production build
${bold(`elm-spa ${cyan(`watch`)}`)} . . . . . . . runs build as you code
${bold(`elm-spa ${cyan(`server`)}`)} . . . . . . start a live dev server
Visit ${green(`https://next.elm-spa.dev`)} for more!
Other commands:
${bold(`elm-spa ${cyan(`gen`)}`)} . . . . generates code without elm make
${bold(`elm-spa ${cyan(`watch`)}`)} . . . . runs elm-spa gen as you code
Visit ${green(`https://elm-spa.dev`)} for more!
`;

@@ -30,13 +30,32 @@ "use strict";

const terminal_1 = require("../terminal");
const readline_1 = require("readline");
// Scaffold a new elm-spa project
exports.default = {
run: () => {
const dest = process.cwd();
File.copy(config_1.default.folders.init, dest);
try {
fs_1.default.renameSync(path_1.default.join(dest, '_gitignore'), path_1.default.join(dest, '.gitignore'));
run: async () => {
return new Promise(offerToInitializeProject);
}
};
const offerToInitializeProject = (resolve, reject) => {
const rl = readline_1.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question(`\n May I create a ${terminal_1.colors.cyan}new project${terminal_1.reset} in the ${terminal_1.colors.yellow}current folder${terminal_1.reset}? ${terminal_1.dim}[y/n]${terminal_1.reset} `, answer => {
if (answer.toLowerCase() === 'n') {
reject(` ${terminal_1.bold}No changes made!${terminal_1.reset}`);
}
catch (_) { }
return ` ${terminal_1.bold}New project created in:${terminal_1.reset}\n ${process.cwd()}`;
else {
resolve(initializeNewProject());
rl.close();
}
});
};
const initializeNewProject = () => {
const dest = process.cwd();
File.copy(config_1.default.folders.init, dest);
try {
fs_1.default.renameSync(path_1.default.join(dest, '_gitignore'), path_1.default.join(dest, '.gitignore'));
}
catch (_) { }
return ` ${terminal_1.check} ${terminal_1.bold}New project created in:${terminal_1.reset}\n ${process.cwd()}\n`;
};

@@ -93,5 +93,5 @@ "use strict";

run: async () => {
const output = await watch_1.watch();
const output = await watch_1.watch(true);
return start().then(serverOutput => [serverOutput, output]);
}
};

@@ -10,4 +10,4 @@ "use strict";

const config_1 = __importDefault(require("../config"));
exports.watch = () => {
const runBuild = build_1.build('development');
exports.watch = (runElmMake) => {
const runBuild = build_1.build({ env: 'development', runElmMake });
chokidar_1.default

@@ -19,2 +19,3 @@ .watch(config_1.default.folders.src, { ignoreInitial: true })

console.info(output);
console.info('');
})

@@ -24,2 +25,3 @@ .catch(reason => {

console.error(reason);
console.info('');
}));

@@ -29,3 +31,3 @@ return runBuild();

exports.default = {
run: exports.watch
run: () => exports.watch(false)
};

@@ -9,2 +9,3 @@ "use strict";

homepage: 'Home_',
redirecting: 'Redirecting_',
notFound: 'NotFound'

@@ -28,2 +29,6 @@ };

generated: path_1.default.join(cwd, '.elm-spa', 'generated'),
templates: {
defaults: path_1.default.join(root, 'src', 'templates', 'add'),
user: path_1.default.join(cwd, '.elm-spa', 'templates')
},
package: path_1.default.join(cwd, '.elm-spa', 'package'),

@@ -33,12 +38,8 @@ public: path_1.default.join(cwd, 'public'),

},
binaries: {
elm: path_1.default.join(root, 'node_modules', '.bin', 'elm'),
terser: path_1.default.join(root, 'node_modules', '.bin', 'terser')
},
defaults: [
['Auth.elm'],
['Effect.elm'],
['Main.elm'],
['Shared.elm'],
[`Pages`, `${reserved.notFound}.elm`],
['Page.elm'],
['Request.elm'],
['View.elm']

@@ -45,0 +46,0 @@ ]

@@ -61,3 +61,3 @@ "use strict";

try {
fs_2.default.mkdirSync(dest);
fs_2.default.mkdirSync(dest, { recursive: true });
}

@@ -64,0 +64,0 @@ catch (_) { }

@@ -12,5 +12,9 @@ #!/usr/bin/env node

build: cli_1.default.build,
gen: cli_1.default.gen,
watch: cli_1.default.watch,
server: cli_1.default.server,
help: cli_1.default.help
help: cli_1.default.help,
// Aliases for Elm folks
init: cli_1.default.new,
make: cli_1.default.build,
};

@@ -17,0 +21,0 @@ const command = process.argv[2];

@@ -5,2 +5,4 @@ "use strict";

const child_process_1 = require("child_process");
exports.run = (cmd) => new Promise((resolve, reject) => child_process_1.exec(cmd, (err, stdout, stderr) => err ? reject(stderr) : resolve(stdout)));
exports.run = (cmd) => new Promise((resolve, reject) => child_process_1.exec(cmd, (err, stdout, stderr) => err
? reject(stderr.split('npm ERR!')[0] || stderr)
: resolve(stdout)));
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = (page) => `
module Pages.${page.join('.')} exposing (page)
module Pages.${page.join('.')} exposing (view)

@@ -9,6 +9,6 @@ import View exposing (View)

page : View Never
page =
view : View msg
view =
View.placeholder "${page.join('.')}"
`.trimLeft();
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const config_1 = __importDefault(require("../config"));
const utils_1 = require("./utils");

@@ -11,4 +15,4 @@ exports.default = (pages, options) => `

${utils_1.pagesModelDefinition(pages, options)}
${utils_1.pagesModelDefinition([[config_1.default.reserved.redirecting]].concat(pages), options)}
`.trimLeft();

@@ -11,4 +11,4 @@ "use strict";

${utils_1.pagesMsgDefinition(pages.filter(path => options.isStatic(path) === false))}
${utils_1.pagesMsgDefinition(pages.filter(path => !options.isStaticView(path)), options)}
`.trimLeft();

@@ -8,3 +8,4 @@ "use strict";

import Browser.Navigation exposing (Key)
import Request exposing (Request)
import Effect exposing (Effect)
import ElmSpa.Page
${utils_1.paramsImports(pages)}

@@ -16,2 +17,3 @@ import Gen.Model as Model

${utils_1.pagesImports(pages)}
import Request exposing (Request)
import Shared

@@ -31,3 +33,3 @@ import Task

init : Route -> Shared.Model -> Url -> Key -> ( Model, Cmd Msg, Cmd Shared.Msg )
init : Route -> Shared.Model -> Url -> Key -> ( Model, Effect Msg )
init route =

@@ -37,5 +39,5 @@ ${utils_1.pagesInitBody(pages)}

update : Msg -> Model -> Shared.Model -> Url -> Key -> ( Model, Cmd Msg, Cmd Shared.Msg )
update : Msg -> Model -> Shared.Model -> Url -> Key -> ( Model, Effect Msg )
update msg_ model_ =
${utils_1.pagesUpdateBody(pages.filter(page => options.isStatic(page) === false), options)}
${utils_1.pagesUpdateBody(pages.filter(page => !options.isStaticView(page)), options)}
${pages.length > 1 ? utils_1.pagesUpdateCatchAll : ''}

@@ -65,45 +67,20 @@

type alias Bundle params model msg =
{ init : params -> Shared.Model -> Url -> Key -> ( Model, Cmd Msg, Cmd Shared.Msg )
, update : params -> msg -> model -> Shared.Model -> Url -> Key -> ( Model, Cmd Msg, Cmd Shared.Msg )
, view : params -> model -> Shared.Model -> Url -> Key -> View Msg
, subscriptions : params -> model -> Shared.Model -> Url -> Key -> Sub Msg
}
ElmSpa.Page.Bundle params model msg Shared.Model (Effect Msg) Model Msg (View Msg)
bundle :
(Shared.Model -> Request params -> Page model msg)
-> (params -> model -> Model)
-> (msg -> Msg)
-> Bundle params model msg
bundle page toModel toMsg =
let
mapTriple :
params
-> ( model, Cmd msg, List Shared.Msg )
-> ( Model, Cmd Msg, Cmd Shared.Msg )
mapTriple params ( model, cmd, sharedMsgList ) =
( toModel params model
, Cmd.map toMsg cmd
, sharedMsgList
|> List.map (Task.succeed >> Task.perform identity)
|> Cmd.batch
)
in
{ init =
\\params shared url key ->
(page shared (Request.create params url key)).init ()
|> mapTriple params
, update =
\\params msg model shared url key ->
(page shared (Request.create params url key)).update msg model
|> mapTriple params
, view =
\\params model shared url key ->
(page shared (Request.create params url key)).view model
|> View.map toMsg
, subscriptions =
\\params model shared url key ->
(page shared (Request.create params url key)).subscriptions model
|> Sub.map toMsg
}
ElmSpa.Page.bundle
{ redirecting =
{ model = Model.Redirecting_
, view = View.none
}
, toRoute = Route.fromUrl
, toUrl = Route.toHref
, fromCmd = Effect.fromCmd
, mapEffect = Effect.map toMsg
, mapView = View.map toMsg
, toModel = toModel
, toMsg = toMsg
, page = page
}

@@ -117,4 +94,4 @@

static view_ toModel =
{ init = \\params _ _ _ -> ( toModel params, Cmd.none, Cmd.none )
, update = \\params _ _ _ _ _ -> ( toModel params, Cmd.none, Cmd.none )
{ init = \\params _ _ _ -> ( toModel params, Effect.none )
, update = \\params _ _ _ _ _ -> ( toModel params, Effect.none )
, view = \\_ _ _ _ _ -> View.map never view_

@@ -121,0 +98,0 @@ , subscriptions = \\_ _ _ _ _ -> Sub.none

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const config_1 = __importDefault(require("../config"));
const utils_1 = require("./utils");
const routeParserOrder = (pages) => [...pages].sort(sorter);
const isHomepage = (list) => list.join('.') === config_1.default.reserved.homepage;
const isDynamic = (piece) => piece.endsWith('_');
const alphaSorter = (a, b) => a < b ? -1 : b < a ? 1 : 0;
const sorter = (a, b) => {
if (isHomepage(a))
return -1;
if (isHomepage(b))
return 1;
if (a.length < b.length)
return -1;
if (a.length > b.length)
return 1;
for (let i in a) {
const [isA, isB] = [isDynamic(a[i]), isDynamic(b[i])];
if (isA && isB)
return alphaSorter(a[i], b[i]);
if (isA)
return 1;
if (isB)
return -1;
}
return 0;
};
exports.default = (pages, _options) => `

@@ -26,3 +54,3 @@ module Gen.Route exposing

routes =
${utils_1.indent(utils_1.routeParserList(pages), 1)}
${utils_1.indent(utils_1.routeParserList(routeParserOrder(pages)), 1)}

@@ -29,0 +57,0 @@

@@ -6,4 +6,10 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.isStaticPage = exports.exposesMsg = exports.exposesModel = exports.pagesSubscriptionsBody = exports.pagesViewBody = exports.pagesUpdateCatchAll = exports.pagesUpdateBody = exports.pagesInitBody = exports.pagesBundleDefinition = exports.pagesBundleAnnotation = exports.pagesMsgDefinition = exports.pagesModelDefinition = exports.pagesImports = exports.paramsImports = exports.routeToHrefSegments = exports.routeToHref = exports.routeParserList = exports.routeTypeDefinition = exports.routeTypeVariant = exports.routeParserMap = exports.routeParser = exports.paramsRouteParserMap = exports.routeParameters = exports.indent = exports.customType = exports.multilineRecord = exports.multilineList = exports.routeVariant = exports.urlArgumentToPages = void 0;
exports.isStaticView = exports.isStaticPage = exports.isStandardPage = exports.exposesViewFunction = exports.exposesPageFunction = exports.exposesMsg = exports.exposesModel = exports.pagesSubscriptionsBody = exports.pagesViewBody = exports.pagesUpdateCatchAll = exports.pagesUpdateBody = exports.pagesInitBody = exports.pagesBundleDefinition = exports.pagesBundleAnnotation = exports.pagesMsgDefinition = exports.pagesModelDefinition = exports.pagesImports = exports.paramsImports = exports.routeToHrefSegments = exports.routeToHref = exports.routeParserList = exports.routeTypeDefinition = exports.routeTypeVariant = exports.routeParserMap = exports.routeParser = exports.paramsRouteParserMap = exports.routeParameters = exports.indent = exports.customType = exports.multilineRecord = exports.multilineList = exports.routeVariant = exports.urlArgumentToPages = exports.options = void 0;
const config_1 = __importDefault(require("../config"));
exports.options = (kind) => ({
kind,
isStaticView: p => kind(p) === 'view',
isStaticPage: p => kind(p) === 'static-page',
isStandardPage: p => kind(p) === 'page',
});
// [ 'Home_' ] => true

@@ -116,19 +122,33 @@ const isHomepage = (path) => path.join('') === config_1.default.reserved.homepage;

const pageModuleName = (path) => `Pages.${path.join('.')}`;
exports.pagesModelDefinition = (paths, options) => exports.customType('Model', paths.map(path => options.isStatic(path)
? `${modelVariant(path)} ${params(path)}`
: `${modelVariant(path)} ${params(path)} ${model(path)}`));
exports.pagesMsgDefinition = (paths) => (paths.length === 0)
exports.pagesModelDefinition = (paths, options) => exports.customType('Model', paths.map(path => (() => {
if (path[0] === config_1.default.reserved.redirecting)
return config_1.default.reserved.redirecting;
switch (options.kind(path)) {
case 'view': return `${modelVariant(path)} ${params(path)}`;
case 'static-page': return `${modelVariant(path)} ${params(path)} ${model(path, options)}`;
case 'page': return `${modelVariant(path)} ${params(path)} ${model(path, options)}`;
}
})()));
exports.pagesMsgDefinition = (paths, options) => (paths.length === 0)
? `type Msg = None`
: exports.customType('Msg', paths.map(path => `${msgVariant(path)} ${msg(path)}`));
: exports.customType('Msg', paths.map(path => `${msgVariant(path)} ${msg(path, options)}`));
exports.pagesBundleAnnotation = (paths, options) => exports.indent(exports.multilineRecord(':', paths.map(path => [
bundleName(path),
options.isStatic(path)
? `Static ${params(path)}`
: `Bundle ${params(path)} ${model(path)} ${msg(path)}`
(() => {
switch (options.kind(path)) {
case 'view': return `Static ${params(path)}`;
case 'static-page': return `Bundle ${params(path)} ${model(path, options)} ${msg(path, options)}`;
case `page`: return `Bundle ${params(path)} ${model(path, options)} ${msg(path, options)}`;
}
})()
])));
exports.pagesBundleDefinition = (paths, options) => exports.indent(exports.multilineRecord('=', paths.map(path => [
bundleName(path),
options.isStatic(path)
? `static ${pageModuleName(path)}.page Model.${modelVariant(path)}`
: `bundle ${pageModuleName(path)}.page Model.${modelVariant(path)} Msg.${msgVariant(path)}`
(() => {
switch (options.kind(path)) {
case 'view': return `static ${pageModuleName(path)}.view Model.${modelVariant(path)}`;
case 'static-page': return `bundle ${pageModuleName(path)}.page Model.${modelVariant(path)} Msg.${msgVariant(path)}`;
case `page`: return `bundle ${pageModuleName(path)}.page Model.${modelVariant(path)} Msg.${msgVariant(path)}`;
}
})()
])));

@@ -138,6 +158,14 @@ const bundleName = (path) => path.map(fromPascalToCamelCase).join('__');

const params = (path) => `${paramsModule(path)}.Params`;
const model = (path) => `Pages.${path.join('.')}.Model`;
const model = (path, options) => {
switch (options.kind(path)) {
case 'view': return `()`;
case 'static-page': return `()`;
case 'page': return `Pages.${path.join('.')}.Model`;
}
};
const modelVariant = (path) => `${path.join('__')}`;
const msgVariant = (path) => `${path.join('__')}`;
const msg = (path) => `Pages.${path.join('.')}.Msg`;
const msg = (path, options) => options.isStandardPage(path)
? `Pages.${path.join('.')}.Msg`
: `Never`;
exports.pagesInitBody = (paths) => exports.indent(caseExpression(paths, {

@@ -155,4 +183,4 @@ variable: 'route',

_ ->
\\_ _ _ -> ( model_, Cmd.none, Cmd.none )`;
exports.pagesViewBody = (paths, options) => exports.indent(caseExpression(paths, {
\\_ _ _ -> ( model_, Effect.none )`;
exports.pagesViewBody = (paths, options) => exports.indent(caseExpressionWithRedirectingModel(`\\_ _ _ -> View.none`, paths, {
variable: 'model_',

@@ -162,3 +190,3 @@ condition: path => `${destructuredModel(path, options)}`,

}));
exports.pagesSubscriptionsBody = (paths, options) => exports.indent(caseExpression(paths, {
exports.pagesSubscriptionsBody = (paths, options) => exports.indent(caseExpressionWithRedirectingModel(`\\_ _ _ -> Sub.none`, paths, {
variable: 'model_',

@@ -168,14 +196,45 @@ condition: path => `${destructuredModel(path, options)}`,

}));
const caseExpressionWithRedirectingModel = (fallback, items, options) => caseExpression([[config_1.default.reserved.redirecting]].concat(items), {
variable: options.variable,
condition: (item) => item[0] === config_1.default.reserved.redirecting
? `Model.${config_1.default.reserved.redirecting}`
: options.condition(item),
result: (item) => item[0] === config_1.default.reserved.redirecting
? fallback
: options.result(item)
});
const caseExpression = (items, options) => `case ${options.variable} of
${items.map(item => ` ${options.condition(item)} ->\n ${options.result(item)}`).join('\n\n')}`;
const destructuredModel = (path, options) => options.isStatic(path)
? `Model.${modelVariant(path)} params`
: `Model.${modelVariant(path)} params model`;
const pageModelArguments = (path, options) => options.isStatic(path)
? `params ()`
: `params model`;
// Used in place of sophisticated AST parsing
const exposes = (keyword) => (elmSourceCode) => new RegExp(`module\\s(\\S)+\\sexposing(\\s)+\\([^\\)]*${keyword}[^\\)]*\\)`, 'm').test(elmSourceCode);
const destructuredModel = (path, options) => {
switch (options.kind(path)) {
case 'view': return `Model.${modelVariant(path)} params`;
case 'static-page': return `Model.${modelVariant(path)} params model`;
case 'page': return `Model.${modelVariant(path)} params model`;
}
};
const pageModelArguments = (path, options) => {
switch (options.kind(path)) {
case 'view': return `params ()`;
case 'static-page': return `params model`;
case 'page': return `params model`;
}
};
const exposes = (value) => (str) => {
const regex = new RegExp('^module\\s+[^\\s]+\\s+exposing\\s+\\(([^)]+)\\)');
const match = (str.match(regex) || [])[1];
if (match) {
return match.split(',').filter(a => a).map(a => a.trim()).includes(value);
}
else {
return false;
}
};
exports.exposesModel = exposes('Model');
exports.exposesMsg = exposes('Msg');
exports.isStaticPage = (sourceCode) => !exports.exposesModel(sourceCode) || !exports.exposesMsg(sourceCode);
exports.exposesPageFunction = exposes('page');
exports.exposesViewFunction = exposes('view');
exports.isStandardPage = (src) => exports.exposesPageFunction(src)
&& exports.exposesModel(src)
&& exports.exposesMsg(src);
exports.isStaticPage = (src) => exports.exposesPageFunction(src);
exports.isStaticView = (src) => exports.exposesViewFunction(src);
{
"name": "elm-spa",
"version": "6.0.0--beta",
"version": "6.0.0",
"description": "single page apps made easy",

@@ -43,4 +43,4 @@ "bin": "dist/src/index.js",

"chokidar": "3.4.2",
"elm": "0.19.1-3",
"mime": "2.4.6",
"node-elm-compiler": "5.0.5",
"terser": "5.3.8",

@@ -47,0 +47,0 @@ "websocket": "1.0.32"

@@ -16,3 +16,3 @@ {

"elm/url": "1.0.0",
"ryannhg/elm-spa": "5.0.0"
"ryannhg/elm-spa": "6.0.0"
},

@@ -19,0 +19,0 @@ "indirect": {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc